text:
// ----------------------------------------------------------------------------
// Copyright 2006-2010, GeoTelematic Solutions, Inc.
// All rights reserved
// ----------------------------------------------------------------------------
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ----------------------------------------------------------------------------
// Change History:
//  2006/03/26  Martin D. Flynn
//     -Initial release
//  2006/04/02  Martin D. Flynn
//     -Added 'format' attribute
//  2006/04/23  Martin D. Flynn
//     -Integrated logging changes made to Print
//  2007/01/25  Martin D. Flynn
//     -Integrated with "OpenGTS"
//  2007/02/28  Martin D. Flynn
//     -Added ability to convert SQL types to standard field types.
//  2007/09/16  Martin D. Flynn
//     -Added static "quote" method to provide a single place where SQL values are quoted.
//  2007/11/28  Martin D. Flynn
//     -Added methods 'isUnsigned()', 'isNumeric()', 'isString()'
//  2008/02/27  Martin D. Flynn
//     -Added 'isDecimal', 'getTypeMask' methods
//  2008/03/12  Martin D. Flynn
//     -Added method 'getEditor'
//  2008/05/14  Martin D. Flynn
//     -Added support for multiple alternate index keys
//  2008/05/20  Martin D. Flynn
//     -Added a 'Locale' aregument to the 'getTitle' method (for Localization purposes).
//     -Additional changes to the optional/required field specification.
//  2008/06/20  Martin D. Flynn
//     -Added support for enum/mask classes and values (used for record editing).
//  2009/01/28  Martin D. Flynn
//     -Added changes to support UTF8 character sets
//  2009/05/01  Martin D. Flynn
//     -Added DateTime datatype
// ----------------------------------------------------------------------------
package org.opengts.dbtools;

import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import java.sql.*;

import org.opengts.util.*;

/**
*** DBField represents a specific field in an SQL table.
**/

public class DBField
{

    // ------------------------------------------------------------------------

    /**
    *** The default 'isRequired' field state.

    *** If 'true', then all fields are considered required, unliess tagged with "optional".

    *** If 'false', then all fields are considered optional, unliess tagged with "required".

    *** (Note: primary/alternate key fields are always considered required).
    **/
    private static final boolean DEFAULT_REQUIRED   = true;

    // ------------------------------------------------------------------------

    public static final String TYPE_BOOLEAN         = DBProvider.TYPE_BOOLEAN;
    public static final String TYPE_INT8            = DBProvider.TYPE_INT8;
    public static final String TYPE_UINT8           = DBProvider.TYPE_UINT8;
    public static final String TYPE_INT16           = DBProvider.TYPE_INT16;
    public static final String TYPE_UINT16          = DBProvider.TYPE_UINT16;
    public static final String TYPE_INT32           = DBProvider.TYPE_INT32;
    public static final String TYPE_UINT32          = DBProvider.TYPE_UINT32;
    public static final String TYPE_INT64           = DBProvider.TYPE_INT64;
    public static final String TYPE_UINT64          = DBProvider.TYPE_UINT64;
    public static final String TYPE_FLOAT           = DBProvider.TYPE_FLOAT;
    public static final String TYPE_DOUBLE          = DBProvider.TYPE_DOUBLE;
    public static final String TYPE_SBLOB           = DBProvider.TYPE_SBLOB;
    public static final String TYPE_BLOB            = DBProvider.TYPE_BLOB;
    public static final String TYPE_MBLOB           = DBProvider.TYPE_MBLOB;
    public static final String TYPE_TEXT            = DBProvider.TYPE_TEXT;
    public static final String TYPE_STRING          = DBProvider.TYPE_STRING;
    public static final String TYPE_DATETIME        = DBProvider.TYPE_DATETIME;

    public static String TYPE_STRING(int n)         { return DBProvider.TYPE_STRING(n); }

    public static String TYPE_STRING(String T,int D) { return DBField.TYPE_STRING(RTConfig.getInt((RTKey.DB_TYPESIZE_ + T), D)); }
    // ie. db.typeSize.address=128
    public static String TYPE_ID()                  { return DBField.TYPE_STRING("ID"           , 32); }
    public static String TYPE_ACCT_ID()             { return DBField.TYPE_STRING("accountID"    , 32); }
    public static String TYPE_USER_ID()             { return DBField.TYPE_STRING("userID"       , 32); }
    public static String TYPE_DEV_ID()              { return DBField.TYPE_STRING("deviceID"     , 32); }
    public static String TYPE_XPORT_ID()            { return DBField.TYPE_STRING("transportID"  , 32); }
    public static String TYPE_GROUP_ID()            { return DBField.TYPE_STRING("groupID"      , 32); }
    public static String TYPE_ROLE_ID()             { return DBField.TYPE_STRING("roleID"       , 32); }
    public static String TYPE_RULE_ID()             { return DBField.TYPE_STRING("ruleID"       , 32); }
    public static String TYPE_CORR_ID()             { return DBField.TYPE_STRING("corridorID"   , 32); }
    public static String TYPE_DRIVER_ID()           { return DBField.TYPE_STRING("driverID"     , 32); }
    public static String TYPE_ENTITY_ID()           { return DBField.TYPE_STRING("entityID"     , 32); }
    public static String TYPE_ZONE_ID()             { return DBField.TYPE_STRING("zoneID"       , 32); }
    public static String TYPE_PROP_ID()             { return DBField.TYPE_STRING("propertyID"   , 32); }
    public static String TYPE_ADDRESS()             { return DBField.TYPE_STRING("address"      , 90); }
    public static String TYPE_EMAIL_LIST()          { return DBField.TYPE_STRING("emailList"    ,128); }

    public static String TYPE_UNIQ_ID()             { return DBField.TYPE_STRING("uniqueID"     , 40); }

    public static String TYPE_DESC()                { return DBField.TYPE_STRING("description"  ,128); }

    // ------------------------------------------------------------------------

    public static final String SQL_AUTO_INCREMENT   = "auto_increment";
    public static final String SQL_NOT_NULL         = "NOT NULL";

    // ------------------------------------------------------------------------
    // EDIT_NEVER   : Never editable (maintained by system)
    // EDIT_NEW     : Only editable when new records are created
    // EDIT_ADMIN   : Editable by admin only
    // EDIT_PUBLIC  : Editable by anyone having access to the data

    public static final int    EDIT_NEVER           = -1;
    public static final int    EDIT_NEW             = 0;
    public static final int    EDIT_ADMIN           = 1;
    public static final int    EDIT_PUBLIC          = 2;

    // ------------------------------------------------------------------------
    // field attributes

    public static final String ATTR_KEY             = "key";        // primary key [Boolean]
    public static final String ATTR_UNIQUE          = "unique";     // unique key [Boolean]
    public static final String ATTR_ALTKEY          = "altkey";     // alternate index key [String]
    public static final String ATTR_OPTIONAL        = "optional";   // optional field [Boolean]
    public static final String ATTR_REQUIRED        = "required";   // required field [Boolean]
    public static final String ATTR_EDIT            = "edit";       // editable mode [Integer:0,1,2]
    public static final String ATTR_FORMAT          = "format";     // format [String]
    public static final String ATTR_ENUM            = "enum";       // enum [String]
    public static final String ATTR_MASK            = "mask";       // mask [String]
    public static final String ATTR_EDITOR          = "editor";     // editor [String]
    public static final String ATTR_PRESEP          = "presep";     // editor pre-separator
    public static final String ATTR_UTF8            = "utf8";       // UTF8 character set [Boolean]
    public static final String ATTR_AUTO_INCR       = "auto";       // auto-increment [Boolean]
    public static final String ATTR_UNITS           = "units";      // Field unit type [String]

    // ------------------------------------------------------------------------

    public static final char   ENUM_TYPE_SEPARATOR  = '|';
    public static final char   ENUM_VALUE_SEPARATOR = ':';

    public static final char   MASK_TYPE_SEPARATOR  = '|';
    public static final char   MASK_VALUE_SEPARATOR = ':';

    public static final char   ALT_INDEX_SEPARATOR  = ',';

    // ------------------------------------------------------------------------

    private static final char  ESCAPE_CHAR          = '\\'; // may be DBProvider dependent!
    private static final char  QUOTE_CHAR           = '\''; // may be DBProvider dependent!

    /**
    *** Quotes and returns the specified String
    *** @param s  The String to quote
    *** @return The quoted String
    **/
    public static String quote(String s)
    {
        return DBField.quote(s, QUOTE_CHAR, true);
    }

    /**
    *** Quotes and returns the specified String
    *** @param s  The String to quote
    *** @param q  The quote character (either ' or ")
    *** @param escapeQuote  True to include embedded quotes with \", false to include embedded quotes with ""
    *** @return The quoted String
    **/
    public static String quote(String s, char q, boolean escapeQuote)
    {
        if (s == null) { s = ""; }
        char ch[] = s.toCharArray();
        int c = 0, len = ch.length;
        StringBuffer qsb = new StringBuffer();
        qsb.append(q);
        for (;c < len; c++) {
            if (ch[c] == q) {
                if (escapeQuote) {
                    qsb.append(ESCAPE_CHAR).append(q);  // \"
                } else {
                    qsb.append(q).append(q);            // ""
                }
            } else
            if (ch[c] == ESCAPE_CHAR) {
                qsb.append(ESCAPE_CHAR).append(ESCAPE_CHAR);
            } else
            if (ch[c] == '\n') {
                qsb.append(ESCAPE_CHAR).append('n');
            } else
            if (ch[c] == '\r') {
                qsb.append(ESCAPE_CHAR).append('r');
            } else
            if (ch[c] == '\t') {
                qsb.append(ESCAPE_CHAR).append('t');
            //} else
            //if (ch[c] == 0x26) {
            //    qsb.append(ESCAPE_CHAR).append('Z'); // MySQL: special case for ^Z
            } else {
                qsb.append(ch[c]);
            }
        }
        qsb.append(q);
        return qsb.toString();
    }

    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------

    private String          name            = "";
    private Class           javaClass       = null;

    private String          sqlType         = null;
    private String          charSet         = "";
    private String          dataType        = "";
    private boolean         isTypeMatch     = false;

    private boolean         isRequired      = DEFAULT_REQUIRED;

    private boolean         isAutoIncr      = false;

    private boolean         isPriKey        = false;
    private boolean         isUniqueKey     = false;
    private String          altIndexNames[] = null;

    private int             typeMask        = DBProvider.DATATYPE_NONE;

    private I18N.Text       i18nTitle       = null;

    private RTProperties    attr            = null;
    private int             editMode        = 0;

    private boolean         enumInit        = false;
    private Class<? extends Enum> enumClass = null;

    private boolean         maskInit        = false;
    private Class<? extends Enum> maskClass = null;

    private DBFactory       factory         = null;

    private Object          defaultValue    = null;

    // ------------------------------------------------------------------------

    /**
    *** Constructor.  Used only by 'DBFactory.getExistingColumns' to load actual tables columns.
    *** @param tableName  The name of the table containing this field
    *** @param colName    The name of this field column
    *** @param sqlType    The SQL field type
    *** @param indexNames A set of index names for this field (may include "PRIMARY")
    **/
    public DBField(String tableName, String colName,
        String sqlType, boolean autoIncr,
        String charSet, Set<String> indexNames)
    {
        // Used for existing column definitions
        this.name        = (colName != null)? colName : "";
        this.javaClass   = null;
        this.sqlType     = (sqlType != null)? sqlType.toUpperCase() : "";
        this.charSet     = (charSet != null)? charSet.toLowerCase() : "";
        this.dataType    = null;    // init below
        this.isTypeMatch = false;   // init below
        this.typeMask    = 0;       // init below
        this.attr        = new RTProperties("");
        this.editMode    = EDIT_NEVER;
        this.isRequired  = true;
        this.i18nTitle   = null;
        this.isAutoIncr  = autoIncr;

        /* primary key */
        if ((indexNames != null) && indexNames.contains(DBProvider.PRIMARY_INDEX_NAME)) {
            this.isPriKey = true;
            indexNames.remove(DBProvider.PRIMARY_INDEX_NAME);
        } else {
            this.isPriKey = false;
        }

        /* unique key */
        if ((indexNames != null) && indexNames.contains(DBProvider.UNIQUE_INDEX_NAME)) {
            this.isUniqueKey = true;
            indexNames.remove(DBProvider.UNIQUE_INDEX_NAME);
        } else {
            this.isUniqueKey = false;
        }

        /* alternate index */
        if ((indexNames != null) && !indexNames.isEmpty()) {
            this.altIndexNames = indexNames.toArray(new String[indexNames.size()]);
        } else {
            this.altIndexNames = null;
        }

        /* check the preferred data type */
        // Different defined data-types may map to the same sql-type.
        // This initialization attempts to set the preferred data-type (as defined by the table wrapper).
        // If the preferred data-type produces an sql-type that matches the incoming sql-type, then set
        // this field's data-type to the preferred data-type
        DBFactory fact = DBFactory.getFactoryByName(tableName);
        if (fact != null) {
            this.setFactory(fact);
            DBField fld = fact.getField(colName);
            if (fld != null) {
                String prefDT = fld.getDataType();      // preferred DataType
                String prefST = fld.getSqlType(false);  // preferred SQLType
                if (prefST.equalsIgnoreCase(this.sqlType)) {
                    // The resulting sql-types are exactly equal, use the preferred data-type
                    this.dataType    = prefDT;
                    this.isTypeMatch = true;
                    this.typeMask    = DBProvider.getDataTypeMask(this.dataType);
                } else {
                    String dbpDT = DBProvider.getDataTypeFromSqlType(this.sqlType);
                    if (DBProvider.areTypesEquivalent(prefDT,dbpDT)) {
                        // The resulting data-types are equivalent, use the preferred data-type
                        this.dataType    = prefDT;
                        this.isTypeMatch = true;
                        this.typeMask    = DBProvider.getDataTypeMask(this.dataType);
                    } else {
                        // preferred/actual types are different
                        this.dataType = dbpDT;
                        Print.logInfo("SQL type mismatch: " + this.sqlType + "[" + dbpDT + "] <==> " + prefST + "[" + prefDT + "]");
                        this.isTypeMatch = false;
                        this.typeMask    = DBProvider.getDataTypeMask(this.dataType);
                    }
                }
            } else {
                // this column doesn't exist in our table definition
                //Print.logInfo("This column is not used in the defined table: " + this.name);
                this.dataType    = DBProvider.getDataTypeFromSqlType(this.sqlType);
                this.isTypeMatch = false;
                this.typeMask    = DBProvider.getDataTypeMask(this.dataType);
            }
        } else {
            // This table doesn't exist in our known list of tables
            this.dataType    = DBProvider.getDataTypeFromSqlType(this.sqlType);
            this.isTypeMatch = false;
            this.typeMask    = DBProvider.getDataTypeMask(this.dataType);
        }

    }

    /**
    *** Constructor.  Used within table definition modules to define fileds/columns.

    *** The file attribute list should specify a String containing a list of "key=value" properties.
    *** The following attribute/property keys may be specified:
    ***

    ***
"key"    - "true" if this field is a primary key (may be omitted otherwise) [ie. "key=true"]

    ***
"altkey" - An alternate index name [ie. "altkey=myIndex"]

    ***
"edit"   - A field edit mode (-1=never, 0=new, 1=administrator, 2=public) [ie. "edit=2"]

    ***
"format" - The default display field format used for reports, etc. [ie. "format=0.000"]

    ***
"enum"   - A reference to the enumerated type for this field, used by a table/field editor [ie. "enum=SpeedUnits"]

    ***
"mask"   - A reference to a bitmasked type for this field, used by a table/field editor [ie. "enum=1:Binary|2:Base64|4:Hex"]

    ***
"editor" - The name of a field editor used by a table/field editor UI [ie. "editor=statusCode"]

    ***
"presep" - Used by the table/field editor UI to insert a separator before this field [ie. "presep=true"]

    ***

    *** @param fldName   The field name
    *** @param javaClass The Java class representation of this field
    *** @param dataType  The field SQL data type
    *** @param title     The displayed field title
    *** @param attr      The field attribute list
    **/
    public DBField(String fldName, Class javaClass, String dataType, String title, String attr)
    {
        this(fldName, javaClass, dataType, new I18N.Text(title), attr);
    }

    /**
    *** Constructor.  Used within table definition modules to define fileds/columns.

    *** The file attribute list should specify a String containing a list of "key=value" properties.
    *** The following attribute/property keys may be specified:
    ***

    ***
"key"    - "true" if this field is a primary key (may be omitted otherwise) [ie. "key=true"]

    ***
"altkey" - An alternate index name [ie. "altkey=myIndex"]

    ***
"edit"   - A field edit mode (-1=never, 0=new, 1=administrator, 2=public) [ie. "edit=2"]

    ***
"format" - The default display field format used for reports, etc. [ie. "format=0.000"]

    ***
"enum"   - A reference to the enumerated type for this field, used by a table/field editor [ie. "enum=SpeedUnits"]

    ***
"mask"   - A reference to a bitmasked type for this field, used by a table/field editor [ie. "enum=1:Binary|2:Base64|4:Hex"]

    ***
"editor" - The name of a field editor used by a table/field editor UI [ie. "editor=statusCode"]

    ***
"presep" - Used by the table/field editor UI to insert a separator before this field [ie. "presep=true"]

    ***

    *** @param fldName   The field name
    *** @param javaClass The Java class representation of this field
    *** @param dataType  The field SQL data type
    *** @param title     The displayed field title
    *** @param attr      The field attribute list
    **/
    public DBField(String fldName, Class javaClass, String dataType, I18N.Text title, String attr)
    {
        // Used by table definitions
        this.name        = (fldName != null)? fldName : "";
        this.javaClass   = javaClass;
        this.sqlType     = null; // always null for 'defined' fields
        this.charSet     = "";   // init below
        this.dataType    = (dataType != null)? dataType.toUpperCase() : "";
        this.isTypeMatch = true; // this field always matches itself
        this.typeMask    = DBProvider.getDataTypeMask(this.dataType);
        this.attr        = new RTProperties((attr != null)? attr : "");
        this.editMode    = this.getIntAttribute(ATTR_EDIT, EDIT_NEVER);
        this.isRequired  = DEFAULT_REQUIRED;
        this.i18nTitle   = title;

        /* character set */
        this.charSet     = (RTConfig.getBoolean(RTKey.DB_UTF8) && this.getBooleanAttribute(ATTR_UTF8,false))? "utf8" : "";

        /* primary key */
        this.isPriKey    = this.getBooleanAttribute(ATTR_KEY,false);

        /* unique key */
        this.isUniqueKey = this.isPriKey || this.getBooleanAttribute(ATTR_UNIQUE,false);

        /* alternate index keys */
        this.altIndexNames = null;
        String akn[] = StringTools.parseString(this.getStringAttribute(ATTR_ALTKEY,null), ALT_INDEX_SEPARATOR); // alt1,alt2,etc
        if ((akn != null) && (akn.length > 0)) {
            // if we're here, then 'altkey' has been specified with a non-empty value
            java.util.List<String> altKeyList = new Vector<String>();
            for (int i = 0; i < akn.length; i++) {
                if (StringTools.isBlank(akn[i])) {
                    // null/empty 'altkey' value
                    Print.logStackTrace("Invalid alternate key specification for field: " + fldName);
                } else
                if (akn[i].equalsIgnoreCase("true") || akn[i].equalsIgnoreCase("yes") || akn[i].equals("1")) {
                    // default 'altkey' value
                    altKeyList.add(DBProvider.DEFAULT_ALT_INDEX_NAME);
                } else
                if (akn[i].equals(DBProvider.DEFAULT_ALT_INDEX_NAME)) {
                    // explicit 'altIndex' default value
                    altKeyList.add(akn[i]);
                } else {
                    // other alternate index name
                    altKeyList.add(akn[i]);
                }
            }
            if (!altKeyList.isEmpty()) {
                this.altIndexNames = altKeyList.toArray(new String[altKeyList.size()]);
            } else {
                // should not be here, since we've prequalified the 'altkey' value list
                // (this is possible if something similar to the following is specified: "altkey=,,,")
            }
        }

        /* required/optional? */
        if (this.isPriKey || this.isUniqueKey || (this.altIndexNames != null)) {
            if (this.getBooleanAttribute(ATTR_OPTIONAL,false)) {
                Print.logWarn("'Optional' specification ignored for key field!");
            }
            this.isRequired = true;
        } else
        if (this.getBooleanAttribute(ATTR_REQUIRED,false)) {
            this.isRequired = true;
        } else
        if (this.getBooleanAttribute(ATTR_OPTIONAL,false)) {
            this.isRequired = false;
        }

        /* auto_increment */
        this.isAutoIncr = this.getBooleanAttribute(ATTR_AUTO_INCR,false);

    }

    // ------------------------------------------------------------------------

    /**
    *** Sets the parent table DBFactory for this field
    *** @param factory  The parent DBFactory instance
    **/
    public void setFactory(DBFactory factory)
    {
        this.factory = factory;
    }

    /**
    *** Gets the parent table DBFactory for this field
    *** @return  The parent DBFactory instance
    **/
    public DBFactory getFactory()
    {
        return this.factory;
    }

    // ------------------------------------------------------------------------

    /**
    *** Gets the Java class for this field
    *** @return  The Java class for this field
    **/
    public Class getTypeClass()
    {
        return this.javaClass;
    }

    /**
    *** Returns true if this field is a String type.
    *** @return True if this field is a String type.
    **/
    public boolean isTypeString()
    {
        return (this.javaClass == String.class);
    }

    /**
    *** Returns true if this field is a Integer type.
    *** @return True if this field is a Integer type.
    **/
    public boolean isTypeInteger()
    {
        return ((this.javaClass == Integer.class) || (this.javaClass == Integer.TYPE));
    }

    /**
    *** Returns true if this field is a Long type.
    *** @return True if this field is a Long type.
    **/
    public boolean isTypeLong()
    {
        return ((this.javaClass == Long.class) || (this.javaClass == Long.TYPE));
    }

    /**
    *** Returns true if this field is a Float type.
    *** @return True if this field is a Float type.
    **/
    public boolean isTypeFloat()
    {
        return ((this.javaClass == Float.class) || (this.javaClass == Float.TYPE));
    }

    /**
    *** Returns true if this field is a Double type.
    *** @return True if this field is a Double type.
    **/
    public boolean isTypeDouble()
    {
        return ((this.javaClass == Double.class) || (this.javaClass == Double.TYPE));
    }

    /**
    *** Returns true if this field is a Boolean type.
    *** @return True if this field is a Boolean type.
    **/
    public boolean isTypeBoolean()
    {
        return ((this.javaClass == Boolean.class) || (this.javaClass == Boolean.TYPE));
    }

    /**
    *** Returns true if this field is a Byte[] type.
    *** @return True if this field is a Byte[] type.
    **/
    public boolean isTypeBLOB()
    {
        return ((this.javaClass == Byte[].class) || (this.javaClass == byte[].class));
    }

    /**
    *** Returns true if this field is a DateTime type.
    *** @return True if this field is a DateTime type.
    **/
    public boolean isTypeDateTime()
    {
        return (this.javaClass == DateTime.class);
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns true if this field is "auto_increment"
    *** @return True if this field is "auto_increment"
    **/
    public boolean isAutoIncrement()
    {
        return this.isAutoIncr;
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns true if this field is required
    *** @return True if this field is required
    **/
    public boolean isRequired()
    {
        return this.isRequired;
    }

    // ------------------------------------------------------------------------

    /**
    *** Gets the column character set
    *** @return The column character set
    **/
    public String getCharacterSet()
    {
        return this.charSet;
    }

    /**
    *** Returns true if this field is defined as character set UTF8
    *** @return True if this field is defined as character set UTF8
    **/
    public boolean isUTF8()
    {
        return (this.charSet != null) && this.charSet.startsWith("utf8");
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns true if this field is a primary key
    *** @return True if this field is a primary key
    **/
    public boolean isPrimaryKey()
    {
        return this.isPriKey;
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns true if this field is a unique key
    *** @return True if this field is a unique key
    **/
    public boolean isUniqueKey()
    {
        return this.isUniqueKey;
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns true if this field is an alternate index key
    *** @return True if this field is an alternate index key
    **/
    public boolean isAlternateKey()
    {
        return ((this.altIndexNames != null) && (this.altIndexNames.length > 0));
    }

    /**
    *** Gets an array of alternate key index names
    *** @return An array of alternate key index names, or null if this field has not alternate keys
    **/
    public String[] getAlternateIndexes()
    {
        return this.isAlternateKey()? this.altIndexNames : null;
    }

    /**
    *** Returns true if this field defines the specified alternate indexes
    *** @param altIndexes  The list of alternate indexes to check
    *** @return True if this field defines the specified alternate indexes
    **/
    public boolean equalsAlternateIndexes(String altIndexes[])
    {
        String altNdx[] = this.getAlternateIndexes();
        if ((altIndexes == null) || (altIndexes.length == 0)) {
            return ((altNdx == null) || (altNdx.length == 0));
        } else
        if ((altNdx == null) || (altNdx.length == 0)) {
            return false;
        } else
        if (altNdx.length != altIndexes.length) {
            return false;
        } else {
            // TODO: probably could stand some optimization
            for (int i = 0; i < altNdx.length; i++) {
                boolean found = false;
                for (int j = 0; j < altIndexes.length; j++) {
                    if (altNdx[i].equals(altIndexes[j])) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    return false;
                }
            }
            return true;
        }
    }

    /**
    *** Returns true if this is a key field (either primary or alternate)
    *** @return True if this is a key field
    **/
    public boolean isKeyField()
    {
        return this.isPrimaryKey() || this.isAlternateKey();
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns true if this field was loaded from the actual table columns
    *** @return True if this field was loaded from the actual table columns
    **/
    public boolean isSqlField()
    {
        return !StringTools.isBlank(this.sqlType);
    }

    // ------------------------------------------------------------------------

    /**
    *** Gets the type mask for this field
    *** @return The type mask for this field
    **/
    public int getTypeMask()
    {
        return this.typeMask;
    }

    /**
    *** Returns true if this is a boolean field
    *** @return True if this is a boolean field
    **/
    public boolean isBoolean()
    {
        return DBProvider.isDataTypeBoolean(this.typeMask);
    }

    /**
    *** Returns true if this is a numeric field (ie. decimal, unsigned, etc)
    *** @return True if this is a numeric field
    **/
    public boolean isNumeric()
    {
        return DBProvider.isDataTypeNumeric(this.typeMask);
    }

    /**
    *** Returns true if this is a decimal (floating point) field
    *** @return True if this is a decimal field
    **/
    public boolean isDecimal()
    {
        return DBProvider.isDataTypeDecimal(this.typeMask);
    }

    /**
    *** Returns true if this is an unsigned integer field
    *** @return True if this is an unsigned integer field
    **/
    public boolean isUnsigned()
    {
        return DBProvider.isDataTypeUnsigned(this.typeMask);
    }

    /**
    *** Returns true if this is a String field
    *** @return True if this is a String field
    **/
    public boolean isString()
    {
        return DBProvider.isDataTypeString(this.typeMask);
    }

    /**
    *** Returns true if this is a binary (blob) field
    *** @return True if this is a binary field
    **/
    public boolean isBinary()
    {
        return DBProvider.isDataTypeBinary(this.typeMask);
    }

    // ------------------------------------------------------------------------

    /**
    *** Sets the data type for this field.

    *** (Allowed only for 'defined' fields)
    *** @param dataType The field data type
    **/
    public void setDataType(String dataType)
    {
        if (!this.isSqlField()) {
            this.dataType = (dataType != null)? dataType.toUpperCase() : "";
            this.typeMask = DBProvider.getDataTypeMask(this.dataType);
        }
    }

    /**
    *** Gets the data type for this field
    *** @return The field data type
    **/
    public String getDataType()
    {
        return this.dataType;
    }

    /**
    *** Returns true if this field matches the defined table field

    *** (only meaningful for fields read from the actual table columns)
    *** @return True if this field matches the defined table field
    **/
    public boolean isTypeMatch()
    {
        return this.isTypeMatch;
    }

    // ------------------------------------------------------------------------

    /**
    *** Gets the SQL type for this field
    *** @return The SQL type for this field
    **/
    public String getSqlType()
    {
        return this.getSqlType(true);
    }

    /**
    *** Gets the SQL type for this field
    *** @param inclNotNull  True to include "NOT NULL" specification, false to strip this specification
    *** @return The SQL type for this field
    **/
    public String getSqlType(boolean inclNotNull)
    {
        if (this.isSqlField()) {
            if (inclNotNull) {
                // return as-is
                return this.sqlType;
            } else {
                // remove "NOT NULL"
                return DBField._removeFieldType(this.sqlType,SQL_NOT_NULL);
            }
        } else {
            String st = DBProvider.getSqlTypeFromDataType(this.getDataType());
            if (this.isPrimaryKey()) {
                if (inclNotNull) {
                    if (DBField._hasFieldType(st,SQL_NOT_NULL)) {
                        // Primary key field already has "NOT NULL"
                        return st;
                    } else {
                        // append "NOT NULL"
                        return st + " " + SQL_NOT_NULL;
                    }
                } else {
                    // remove existing "NOT NULL" specification
                    return DBField._removeFieldType(st,SQL_NOT_NULL);
                }
            } else {
                if (inclNotNull) {
                    // return string as-is
                    return st;
                } else {
                    // remove existing "NOT NULL" specification
                    return DBField._removeFieldType(st,SQL_NOT_NULL);
                }
            }
        }
    }

    /**
    *** Returns true if 'target' contains 'match'
    **/
    private static boolean _hasFieldType(String target, String match)
    {
        int p = target.toUpperCase().indexOf(match.toUpperCase());
        return (p >= 0);
    }

    /**
    *** Removes 'match' String from 'target' String
    **/
    private static String _removeFieldType(String target, String match)
    {
        int p = target.toUpperCase().indexOf(match.toUpperCase());
        if (p >= 0) {
            return target.substring(0,p).trim() + target.substring(p + match.length());
        } else {
            return target;
        }
    }

    // ------------------------------------------------------------------------

    /**
    *** Gets the String length of this field, or '0' if the field is not a String
    *** @return The length of the String field
    **/
    public int getLength()
    {
        String dt = this.getDataType(); // already uppercase
        if (dt.startsWith(TYPE_STRING + "[")) {
            String x = dt.substring(TYPE_STRING.length() + 1);
            int len = StringTools.parseInt(x, 32);
            return len;
        } else {
            return 0;
        }
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns true if this field type is TEXT/CLOB
    *** @return True if this field type is TEXT/CLOB
    **/
    public boolean isCLOB()
    {
        String dt = this.getDataType(); // already uppercase
        return
            dt.equalsIgnoreCase(TYPE_TEXT);
    }

    /**
    *** Returns true if this field type is binary/BLOB
    *** @return True if this field type is binary/BLOB
    **/
    public boolean isBLOB()
    {
        String dt = this.getDataType(); // already uppercase
        return
            dt.equalsIgnoreCase(TYPE_SBLOB) ||
            dt.equalsIgnoreCase(TYPE_BLOB)  ||
            dt.equalsIgnoreCase(TYPE_MBLOB);
    }

    private static boolean ALLOW_ESCAPE_CHARACTERS_IN_ASCII_BLOB = false;
    private static byte EMPTY_BLOB[] = new byte[0];

    /**
    *** Parses and returns a BLOB (byte[]) representation of the String value
    *** @param val  The String value to parse
    *** @return The BLOB/byte[] representation
    **/
    public static byte[] parseBlobString(String val)
    {
        return DBField.parseBlobString(val, EMPTY_BLOB);
    }

    /**
    *** Parses and returns a BLOB (byte[]) representation of the String value
    *** @param val  The String value to parse
    *** @param dftBlob  The default value returned if the String cannot be parsed
    *** @return The BLOB/byte[] representation
    **/
    public static byte[] parseBlobString(String val, byte dftBlob[])
    {

        /* null/empty value? */
        if (val == null) {
            return dftBlob;
        }

        /* standard Hex representation */
        if (val.startsWith("0x") || val.startsWith("0X")) {
            return StringTools.parseHex(val, dftBlob);
        }

        /* parse as escaped string */
        // parse as a string of characters
        //Print.logInfo("Parsing BLOB String: " + val);
        char ch[] = val.toCharArray();
        byte ba[] = new byte[ch.length];
        int b = 0;
        for (int i = 0; i < ch.length; i++) {
            if (ALLOW_ESCAPE_CHARACTERS_IN_ASCII_BLOB) {
                if ((ch[i] == '\\') && ((i + 1) < ch.length)) {
                    i++; // skip past '\\'
                    if (ch[i] == '0') { // "\0"
                        ba[b++] = (byte)0;
                    } else
                    if (ch[i] == 'r') { // "\r"
                        ba[b++] = '\r';
                    } else
                    if (ch[i] == 'n') { // "\n"
                        ba[b++] = '\n';
                    } else
                    if (ch[i] == 't') { // "\t"
                        ba[b++] = '\t';
                    } else {
                        ba[b++] = (byte)ch[i];
                    }
                } else {
                    ba[b++] = (byte)ch[i];
                }
            } else {
                ba[b++] = (byte)ch[i];
            }
        }
        if (b < ba.length) {
            byte bb[] = new byte[b];
            System.arraycopy(ba, 0, bb, 0, b);
            ba = bb;
        }
        //Print.logInfo("Returned BLOB length = " + ba.length);
        return ba;

    }

    // ------------------------------------------------------------------------

    /**
    *** Extracts and returns the value for this field from the specified ResultSet
    *** @param rs  The ResultSet from which the value is extracted
    *** @return The extracted value for this field
    **/
    @SuppressWarnings("deprecation")
    public Object getResultSetValue(ResultSet rs)
        throws SQLException
    {
        String n = this.getName();
        Class<?> jvc = this.getTypeClass();
        if (jvc == String.class) {
            return (rs != null)? rs.getString(n) : "";
        } else
        if ((jvc == Integer.class) || (jvc == Integer.TYPE)) {
            return new Integer((rs != null)? rs.getInt(n) : 0);
        } else
        if ((jvc == Long.class) || (jvc == Long.TYPE)) {
            return new Long((rs != null)? rs.getLong(n) : 0L);
        } else
        if ((jvc == Float.class) || (jvc == Float.TYPE)) {
            return new Float((rs != null)? rs.getFloat(n) : 0.0F);
        } else
        if ((jvc == Double.class) || (jvc == Double.TYPE)) {
            return new Double((rs != null)? rs.getDouble(n) : 0.0);
        } else
        if ((jvc == Boolean.class) || (jvc == Boolean.TYPE)) {
            return new Boolean((rs != null)? (rs.getInt(n) != 0) : false);
        } else
        if ((jvc == Byte[].class) || (jvc == byte[].class)) {
            return (rs != null)? rs.getBytes(n) : new byte[0];
        } else
        if (jvc == DateTime.class) {
            // Note: the retrieved date should be in the UTC timezone.  The following
            // extracts the YYYY-MM-DD, hh:mm:ss, then explicitly creates a DateTime
            // instance with the UTC/GMT timezone.
            java.sql.Timestamp ts = (rs != null)? rs.getTimestamp(n) : null;
            if (ts != null) {
                int YY = ts.getYear() + 1900;
                int MM = ts.getMonth() + 1;
                int DD = ts.getDate();
                int hh = ts.getHours();
                int mm = ts.getMinutes();
                int ss = ts.getSeconds();
                return new DateTime(DateTime.getGMTTimeZone(), YY,MM,DD, hh,mm,ss);
            } else {
                return new DateTime(0L, DateTime.getGMTTimeZone());
            }
        } else
        if (DBFieldType.class.isAssignableFrom(jvc)) {
            try {
                Constructor<?> dbftConst = jvc.getConstructor(ResultSet.class, String.class);
                return dbftConst.newInstance(new Object[] { rs, n });
            } catch (Throwable t) { // NPE, NoSuchMethodException, InstantiationException, InvocationTargetException, etc.
                if (t instanceof SQLException) {
                    // this will not occur, but we check anyway
                    throw (SQLException)t; // re-throw SQLExceptions
                } else
                if (t.getCause() instanceof SQLException) {
                    // This will typically be wrapped inside a 'InvocationTargetException'
                    throw (SQLException)t.getCause(); // re-throw SQLExceptions
                }
                Print.logException("Unable to instantiate", t);
                return null;
            }
        } else {
            Print.logError("Unsupported Java class: " + StringTools.className(jvc));
            return null;
        }
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns the field value from the specified DBRecord
    *** @param rcd  The DBRecord from which the value is returned
    *** @return The returned value for this field
    **/
    public Object getFieldValue(DBRecord rcd)
    {
        return (rcd != null)? rcd.getFieldValue(this.getName()) : null;
    }

    // ------------------------------------------------------------------------

    /**
    *** Parses the specified String and returns an Object appropriate for this field data type
    *** @param val  The String value to parse
    *** @return An Object value appropriate for this field data type
    **/
    public Object parseStringValue(String val)
    {
        Class<?> jvc = this.getTypeClass();
        if (jvc == String.class) {
            return (val != null)? val : "";
        } else
        if ((jvc == Integer.class) || (jvc == Integer.TYPE)) {
            return new Integer(StringTools.parseInt(val,0));
        } else
        if ((jvc == Long.class) || (jvc == Long.TYPE)) {
            return new Long(StringTools.parseLong(val,0L));
        } else
        if ((jvc == Float.class) || (jvc == Float.TYPE)) {
            return new Float(StringTools.parseFloat(val,0.0F));
        } else
        if ((jvc == Double.class) || (jvc == Double.TYPE)) {
            return new Double(StringTools.parseDouble(val,0.0));
        } else
        if ((jvc == Boolean.class) || (jvc == Boolean.TYPE)) {
            return new Boolean(StringTools.parseBoolean(val,false));
        } else
        if ((jvc == Byte[].class) || (jvc == byte[].class)) {
            return DBField.parseBlobString(val);
        } else
        if (jvc == DateTime.class) {
            try { // "2009-12-12 12:12:00 TMZ"
                DateTime.ParsedDateTime pdt = DateTime.parseDateTime(val, DateTime.getGMTTimeZone(), DateTime.DefaultParsedTime.DayStart);
                return pdt.createDateTime();
            } catch (DateTime.DateParseException dpe) {
                return new DateTime(0L);
            }
        } else
        if (DBFieldType.class.isAssignableFrom(jvc)) {
            //Print.logInfo("Parsing DBFieldType: " + StringTools.className(jvc) + " >" + val + " [" + val.length() + "]");
            try {
                Constructor<?> dbftConst = jvc.getConstructor(String.class);
                return dbftConst.newInstance(new Object[] { val });
            } catch (Throwable t) {
                // NPE, NoSuchMethodException, InstantiationException, InvocationTargetException, etc.
                Print.logError("Unable to obtain proper constructor: " + t);
                return null;
            }
        } else {
            Print.logError("Unsupported Java class: " + StringTools.className(jvc));
            return null;
        }
    }

    // ------------------------------------------------------------------------

    /**
    *** Sets a default value for this field
    *** Note: The data type of the specified default value is assumed to be
    *** correct for this field type.
    *** @param val  The default value
    **/
    public void setDefaultValue(Object val)
    {
        this.defaultValue = val;
    }

    /**
    *** Returns true if an explicit default value has been defined for this field
    *** @return True if an explicit default value has been defined for this field
    **/
    public boolean _hasDefaultValue()
    {
        return (this.defaultValue != null);
    }

    /**
    *** Gets the explicitly defined default value for this field
    *** @return The explicitly defined default field value
    **/
    public Object _getDefaultValue()
    {
        return this.defaultValue;
    }

    /**
    *** Gets a default value for this field
    *** @return A default field value
    **/
    public Object getDefaultValue()
    {
        if (this.defaultValue != null) {
            return this.defaultValue;
        } else {
            try {
                return this.getResultSetValue(null);
            } catch (SQLException sqe) {
                // this will(should) never occur
                return null;
            }
        }
    }

    /**
    *** Returns true if the specified value matches a default value
    *** (currently, there can be only one default value)
    *** @return True if the specified value matches a default value
    **/
    public boolean isDefaultValue(Object val)
    {
        if (val == null) {
            return false;
        } else
        if (this._hasDefaultValue()) {
            return val.equals(this._getDefaultValue());
        } else {
            return false;
        }
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns true if values represented by this field data type must be quoted
    *** @return True if values represented by this field data type must be quoted
    **/
    public boolean quoteValue()
    {
        if (this.isCLOB()) {
            return true; // TYPE_TEXT
        } else
        if (this.isBLOB()) {
            // This assumes that the value is presented in raw hex form.
            // If the value is presented in hex, quoting may produce invalid results.
            return true; // TYPE_SBLOB || TYPE_BLOB || TYPE_MBLOB
        } else
        if (this.isTypeDateTime()) {
            return true; // TYPE_DATETIME
        } else {
            String dt = this.getDataType(); // already uppercase
            return dt.startsWith(TYPE_STRING);
        }
    }

    /**
    *** Returns a quoted String value for the specified object
    *** @param v  The Object to quote
    *** @return The quoted String value
    **/
    public String getQValue(Object v)
    {
        String vs = DBFieldValues.toStringValue(v);
        if (this.isBLOB()) {
            int dbid = DBProvider.getProvider().getID();
            if (dbid == DBProvider.DB_DERBY) {
                // Derby: CAST(x'FFFF' AS BLOB)
                String hex = vs.startsWith("0x")? vs.substring(2) : vs;
                // TODO: make sure 'hex' contains only valid hex characters
                // (StringTools.hexLength(hex) == hex.length())
                return "CAST(x'" + hex + "' AS BLOB)";
            } else {
                // DBProvider.DB_DERBY
                // MySQL: 0xFFFF
                if (vs.equals("") || vs.equalsIgnoreCase("0x")) {
                    return DBField.quote("");
                } else {
                    String hex = vs.startsWith("0x")? vs : ("0x" + vs);
                    // TODO: make sure 'hex' contains only valid hex characters
                    // (StringTools.hexLength(hex) == hex.length())
                    return hex;
                }
            }
        } else {
            return (this.quoteValue() || vs.equals(""))? DBField.quote(vs) : vs;
        }
    }

    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
    *** Returns true if this field contains the specified attribute
    *** @param key  The attribute key
    *** @return True if this field contains the specified attribute
    **/
    public boolean hasAttribute(String key)
    {
        return this.attr.hasProperty(key);
    }

    /**
    *** Returns the boolean value of the specified attribute key
    *** @param key  The attribute key
    *** @param dft  The default boolean value if the attribute key does not exist
    *** @return The boolean value of the specified attribute key
    **/
    public boolean getBooleanAttribute(String key, boolean dft)
    {
        return this.hasAttribute(key)? this.attr.getBoolean(key,true) : dft;
    }

    /**
    *** Returns the integer value of the specified attribute key
    *** @param key  The attribute key
    *** @param dft  The default integer value if the attribute key does not exist
    *** @return The integer value of the specified attribute key
    **/
    public int getIntAttribute(String key, int dft)
    {
        return this.attr.getInt(key, dft);
    }

    /**
    *** Returns the String value of the specified attribute key
    *** @param key  The attribute key
    *** @param dft  The default 'String' if the attribute key is not defined
    *** @return The String value of the specified attribute key
    **/
    public String getStringAttribute(String key, String dft)
    {
        return this.attr.getString(key, dft);
    }

    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
    *** Sets the 'format' String attribute
    *** @param format The 'format' String attribute
    **/
    public void setFormat(String format)
    {
        this.attr.setString(ATTR_FORMAT, format);
    }

    /**
    *** Returns the 'format' String attribute
    *** @return The 'format' String attribute
    **/
    public String getFormat()
    {
        return this.getFormat(null);
    }

    /**
    *** Returns the 'format' String attribute
    *** @param dft  The default 'format' returned if undefined
    *** @return The 'format' String attribute
    **/
    public String getFormat(String dft)
    {
        String fmt = this.getStringAttribute(ATTR_FORMAT, dft);
        if ((fmt != null) && fmt.startsWith("X")) {
            DBProvider dbp = DBProvider.getProvider();
            if (dbp.getID() == DBProvider.DB_DERBY) { return null; }
        }
        return fmt;
    }

    /**
    *** Returns the specified value as a String formatted appropriately for this field type
    *** @param val  The value to format
    *** @return The formated value
    **/
    public String formatValue(Object val)
    {

        /* null value? */
        if (val == null) {
            return null;
        }

        /* type */
        Class typeClass = this.getTypeClass();

        /* String? */
        if (typeClass == String.class) {
            return val.toString();
        }

        /* format */
        String fmt = this.getFormat();
        if (StringTools.isBlank(fmt)) {
            fmt = null;
        }

        /* numeric */
        if (val instanceof Number) {
            if ((typeClass == Double.class) || (typeClass == Double.TYPE)) {
                double d = ((Number)val).doubleValue();
                return (fmt == null)? String.valueOf(d) : StringTools.format(d,fmt);
            } else
            if ((typeClass == Float.class) || (typeClass == Float.TYPE)) {
                float d = ((Number)val).floatValue();
                return (fmt == null)? String.valueOf(d) : StringTools.format(d,fmt);
            } else
            if ((typeClass == Long.class) || (typeClass == Long.TYPE)) {
                long d = ((Number)val).longValue();
                return (fmt == null)? String.valueOf(d) : StringTools.format(d,fmt);
            } else
            if ((typeClass == Integer.class) || (typeClass == Integer.TYPE)) {
                int d = ((Number)val).intValue();
                return (fmt == null)? String.valueOf(d) : StringTools.format(d,fmt);
            }
            if ((typeClass == Short.class) || (typeClass == Short.TYPE)) {
                int d = ((Number)val).shortValue();
                return (fmt == null)? String.valueOf(d) : StringTools.format(d,fmt);
            }
        }

        /* byte array */
        if (val instanceof byte[]) {
            String hex = StringTools.toHexString((byte[])val);
            return "0x" + hex;
        }

        /* DateTime */
        if (val instanceof DateTime) {
            DateTime dt = (DateTime)val;
            return dt.format("yyyy-MM-dd HH:mm:ss", DateTime.getGMTTimeZone());
        }

        /* default value */
        return val.toString();

    }

    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
    *** Returns true if the specified object is equivalent to this DBField
    *** @return True if the specified object is equivalent to this DBField
    **/
    public boolean equals(Object other)
    {
        if (!(other instanceof DBField)) {
            return false;
        }
        DBField fld = (DBField)other;

        /* check field name */
        if (!this.getName().equals(fld.getName())) {
            return false;
        }

        /* check keys */
        if (this.isPrimaryKey() != fld.isPrimaryKey()) {
            return false;
        } else
        if (this.isAlternateKey() != fld.isAlternateKey()) {
            return false;
        } else
        if (!this.equalsAlternateIndexes(fld.getAlternateIndexes())) {
            return false;
        }

        /* characer set */
        if (this.isUTF8() != fld.isUTF8()) {
            return false;
        }

        /* check data type */
        String thisDT = this.getDataType();
        String othrDT = fld.getDataType();
        if (!thisDT.equals(othrDT)) {
            /* special case for checking fields retrieved directly from the table */
            // if either field is from the SQL table, then TYPE_INT8 is the same as TYPE_BOOLEAN.
            boolean thisBool = (this.isSqlField() && thisDT.equals(TYPE_INT8)) || thisDT.equals(TYPE_BOOLEAN);
            boolean othrBool = ( fld.isSqlField() && othrDT.equals(TYPE_INT8)) || othrDT.equals(TYPE_BOOLEAN);
            if (!thisBool || !othrBool) {
                return false;
            }
        }

        /* match */
        return true;

    }

    // ------------------------------------------------------------------------

    /**
    *** Gets the field name
    *** @return  The field name
    **/
    public String getName()
    {
        return DBProvider.translateColumnName(this.name);
    }

    /**
    *** Gets the SQL definition of this field
    *** (NOTE: does not contain character set information!)
    *** @return The SQL definition of this field
    **/
    public String getFieldDefinition()
    {
        // This is used by "DBFactory._createTable()"
        return this.getName() + " " + this.getSqlType();
    }

    /**
    *** Returns a String representation of this field (for display purposes only)
    *** @return A String representation of this field
    **/
    public String toString()
    {
        StringBuffer sb = new StringBuffer();
        sb.append(this.getFieldDefinition());
        this._getIndexNames(sb);
        return sb.toString();
    }

    // ------------------------------------------------------------------------

    /**
    *** Returns a String list of index names for this field (for display purposes only)
    *** @return A String list of index names for this field
    **/
    public String getIndexNames()
    {
        StringBuffer sb = this._getIndexNames(null);
        return (sb != null)? sb.toString() : "";
    }

    /**
    *** Returns a String list of index names for this field (for display purposes only)
    *** @param sb  The StringBuffer where the index names will be placed
    *** @return The StringBuffer where the index names were placed
    **/
    protected StringBuffer _getIndexNames(StringBuffer sb)
    {
        boolean priKey = this.isPrimaryKey();
        boolean altKey = this.isAlternateKey();
        if (!priKey && !altKey) {
            return sb;
        } else {
            if (sb == null) { sb = new StringBuffer(); }
            if (sb.length() > 0) { sb.append(" "); }
            if (priKey) {
                sb.append(DBProvider.PRIMARY_INDEX_NAME);
            }
            if (altKey) {
                if (priKey) { sb.append(","); }
                sb.append(StringTools.join(this.getAlternateIndexes(),","));
            }
            return sb;
        }
    }

    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
    *** Sets the I18N title for this field
    *** @param title  The I18N title for this field
    **/
    public void setTitle(I18N.Text title)
    {
        this.i18nTitle = title;
    }

    /**
    *** Gets the I18N title for this field
    *** @return  The I18N title for this field
    **/
    public I18N.Text getTitle()
    {
        return this.i18nTitle;
    }

    /**
    *** Returns the 'title' String attribute
    *** @param locale The Locale used for Localization purposes
    *** @return The 'title' String attribute
    **/
    public String getTitle(Locale locale)
    {
        return (this.i18nTitle != null)? this.i18nTitle.toString(locale) : "";
    }

    // ------------------------------------------------------------------------

    /**
    *** Sets the edit mode for this field
    *** @param mode  The edit mode for this field
    **/
    public void setEditMode(int mode)
    {
        switch (mode) {
            case EDIT_NEVER : // -1;
            case EDIT_NEW   : // 0;
            case EDIT_ADMIN : // 1;
            case EDIT_PUBLIC: // 2;
                this.editMode = mode;
                break;
            default         :
                this.editMode = EDIT_NEVER;
                break;
        }
    }

    /**
    *** Gets the edit mode for this field
    *** @return  The edit mode for this field
    **/
    public int getEditMode()
    {
        return this.editMode;
    }

    /**
    *** Returns true if this field is editable for the specified mode
    *** @param mode  The edit mode
    *** @return True if this field is editable for the specified mode
    **/
    public boolean isEditable(int mode)
    {
        DBFactory dbf = this.getFactory();
        if ((dbf != null) && !dbf.isEditable()) {
            return false;
        } else {
            return (mode <= this.editMode);
        }
    }

    /**
    *** Gets the field editor name
    *** @return The field editor name
    **/
    public String getEditor()
    {
        return this.getStringAttribute(ATTR_EDITOR, null);
    }

    // ------------------------------------------------------------------------

    /**
    *** Return the defined Enum class type for this field
    *** @return The Enum class defined for this field
    **/
    public Class<? extends Enum> getEnumClass()
    {
        if (!this.enumInit) {
            this.enumInit = true;
            String enumValue = this.getStringAttribute(ATTR_ENUM, null);
            if (!StringTools.isBlank(enumValue)) {
                if (enumValue.indexOf("$") < 0) {
                    DBFactory fact = this.getFactory();
                    if (fact != null) {
                        this.enumClass = EnumTools.getEnumClass(fact.getRecordClass(), enumValue);
                    }
                }
                if (this.enumClass == null) {
                    this.enumClass = EnumTools.getEnumClass(enumValue);
                }
                if (this.enumClass != null) {
                    Enum e[] = this.enumClass.getEnumConstants();
                    if ((e == null) || (e.length == 0)) {
                        this.enumClass = null;
                    }
                }
                if (this.enumClass == null) {
                    Print.logWarn("Enum class not found: [%s] %s", this.getName(), enumValue);
                }
            }
        }
        return this.enumClass; // may be null
    }

    /**
    *** Gets the map of the valid enumerated values for this field
    *** @return The map of the valid enumerated values for this field, or null if undefined
    **/
    public OrderedMap<String,Integer> getEnumValues()
    {

        /* look up the registered Enum name */
        Class<? extends Enum> eclz = this.getEnumClass();
        if (eclz != null) {
            Enum e[] = eclz.getEnumConstants();
            OrderedMap<String,Integer> map = new OrderedMap<String,Integer>();
            for (int n = 0; n < e.length; n++) {
                if (e[n] instanceof EnumTools.IntValue) {
                    map.put(e[n].toString(), ((EnumTools.IntValue)e[n]).getIntValue());
                }
            }
            if (!map.isEmpty()) {
                return map;
            } else {
                Print.logError("No emunerated values found for field: " + this.getName());
                return null;
            }
        }

        /* custom Enum values */
        String enumValue = this.getStringAttribute(ATTR_ENUM, null);
        if (!StringTools.isBlank(enumValue) && (enumValue.indexOf(ENUM_VALUE_SEPARATOR) >= 0)) {
            String ev[] = StringTools.parseString(enumValue, ENUM_TYPE_SEPARATOR);
            if (ev.length > 0) {
                OrderedMap<String,Integer> map = new OrderedMap<String,Integer>();
                for (int i = 0; i < ev.length; i++) {
                    String v[] = StringTools.parseString(ev[i], ENUM_VALUE_SEPARATOR);
                    if ((v.length >= 2) && !StringTools.isBlank(v[1])) {
                        int n = StringTools.parseInt(v[0],0);
                        map.put(v[1], new Integer(n));
                    }
                }
                return !map.isEmpty()? map : null;
            } else {
                return null;
            }
        }

        /* not found */
        return null;

    }

    // ------------------------------------------------------------------------

    /**
    *** Return the defined Enum bitmask class type for this field
    *** @return The Enum bitmask class defined for this field
    **/
    public Class<? extends Enum> getMaskClass()
    {
        if (!this.maskInit) {
            this.maskInit = true;
            String maskValue = this.getStringAttribute(ATTR_MASK, null);
            if (!StringTools.isBlank(maskValue)) {
                if (maskValue.indexOf("$") < 0) {
                    DBFactory fact = this.getFactory();
                    if (fact != null) {
                        this.maskClass = EnumTools.getEnumClass(fact.getRecordClass(), maskValue);
                    }
                }
                if (this.maskClass == null) {
                    this.maskClass = EnumTools.getEnumClass(maskValue);
                }
                if (this.maskClass != null) {
                    Enum e[] = this.maskClass.getEnumConstants();
                    if ((e == null) || (e.length == 0)) {
                        this.maskClass = null;
                    } else
                    if (!EnumTools.BitMask.class.isAssignableFrom(this.maskClass)) {
                        this.maskClass = null;
                    }
                }
                if (this.maskClass == null) {
                    Print.logWarn("Mask class not found: [%s] %s", this.getName(), maskValue);
                }
            }
        }
        return this.maskClass; // may be null
    }

    /**
    *** Gets the map of the valid enumerated values for this field
    *** @return The map of the valid enumerated values for this field, or null if undefined
    **/
    public OrderedMap<String,Long> getMaskValues()
    {

        /* look up the registered Enum name */
        Class<? extends Enum> eclz = this.getMaskClass();
        if ((eclz != null) && EnumTools.BitMask.class.isAssignableFrom(eclz)) {
            Enum e[] = eclz.getEnumConstants();
            OrderedMap<String,Long> map = new OrderedMap<String,Long>();
            for (int n = 0; n < e.length; n++) {
                map.put(e[n].toString(), ((EnumTools.BitMask)e[n]).getLongValue());
            }
            if (!map.isEmpty()) {
                return map;
            } else {
                Print.logError("No emunerated values found for field: " + this.getName());
                return null;
            }
        }

        /* custom Enum values */
        String maskValue = this.getStringAttribute(ATTR_MASK, null);
        if (!StringTools.isBlank(maskValue) && (maskValue.indexOf(MASK_VALUE_SEPARATOR) >= 0)) {
            String ev[] = StringTools.parseString(maskValue, MASK_TYPE_SEPARATOR);
            if (ev.length > 0) {
                OrderedMap<String,Long> map = new OrderedMap<String,Long>();
                for (int i = 0; i < ev.length; i++) {
                    String v[] = StringTools.parseString(ev[i], MASK_VALUE_SEPARATOR);
                    if ((v.length >= 2) && !StringTools.isBlank(v[1])) {
                        long n = StringTools.parseLong(v[0],0L);
                        map.put(v[1], n);
                    }
                }
                return !map.isEmpty()? map : null;
            } else {
                return null;
            }
        }

        /* not found */
        return null;

    }

    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------

    /*
    public static final String HIB_BOOLEAN      = "boolean";           //  8bit          Java 'boolean'
    public static final String HIB_INT8         = "byte";              //  8bit (signed) Java 'byte'
    public static final String HIB_UINT8        = "unsigned byte";     //  8bit          Java 'byte'
    public static final String HIB_INT16        = "short";             // 16bit (signed)
    public static final String HIB_UINT16       = "unsigned short";    // 16bit (signed)
    public static final String HIB_INT32        = "integer";           // 32bit (signed) Java 'int'
    public static final String HIB_UINT32       = "unsigned integer";  // 32bit          Java 'int'
    public static final String HIB_INT64        = "long";              // 64bit (signed) Java 'long'
    public static final String HIB_UINT64       = "unsigned long";     // 64bit          Java 'long'
    public static final String HIB_FLOAT        = "float";
    public static final String HIB_DOUBLE       = "double";
    public static final String HIB_BINARY       = "binary";            // max (2^16 - 1) bytes
    public static final String HIB_MBLOB        = "bin24";             // max (2^24 - 1) bytes
    public static final String HIB_TEXT         = "text";              // max (2^16 - 1) bytes
    public static final String HIB_STRING       = "string";
    public static String HIB_STRING(int size) { return HIB_STRING + "(" + size + ")"; }

    private String _getHibernateType()
    {
        String dt = this.getDataType();
        if (dt.equals(TYPE_BOOLEAN)) {
            return HIB_BOOLEAN;
        } else
        if (dt.equals(TYPE_INT8)) {
            return HIB_INT8;
        } else
        if (dt.equals(TYPE_UINT8)) {
            return HIB_UINT8;
        } else
        if (dt.equals(TYPE_INT16)) {
            return HIB_INT16;
        } else
        if (dt.equals(TYPE_UINT16)) {
            return HIB_UINT16;
        } else
        if (dt.equals(TYPE_INT32)){
            return HIB_INT32;
        } else
        if (dt.equals(TYPE_UINT32)) {
            return HIB_UINT32;
        } else
        if (dt.equals(TYPE_INT64)) {
            return HIB_INT64;
        } else
        if (dt.equals(TYPE_UINT64)) {
            return HIB_UINT64;
        } else
        if (dt.equals(TYPE_FLOAT)) {
            return HIB_FLOAT;
        } else
        if (dt.equals(TYPE_DOUBLE)) {
            return HIB_DOUBLE;
        } else
        if (dt.equals(TYPE_BLOB)) {
            return HIB_BINARY;
        } else
        if (dt.equals(TYPE_MBLOB)) {
            return HIB_MBLOB;
        } else
        if (dt.equals(TYPE_TEXT)) {
            return HIB_TEXT;
        } else
        if (dt.startsWith(TYPE_STRING + "[")) {
            //String x = dt.substring(TYPE_STRING.length() + 1);
            //int len = StringTools.parseInt(x, 32);
            //return HIB_STRING(len);
            return HIB_STRING;
        } else {
            Print.logError("Unrecognized type: " + dt);
            return HIB_STRING(32);
        }
    }

    public String getHibernateType()
    {
        String hibType = _getHibernateType();
        return hibType;
    }
    */

    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------

    public static void main(String argv[])
    {
        RTConfig.setCommandLineArgs(argv);

        String s = "This is a ("+SQL_NOT_NULL+") test";
        Print.sysPrintln("%s", s);
        if (DBField._hasFieldType(s,SQL_NOT_NULL)) {
            Print.sysPrintln("==> %s", DBField._removeFieldType(s,SQL_NOT_NULL));
        }

    }

}


text:
'''
10. Using ciscoconfparse find the crypto maps that are not using AES (based-on the transform set name).
Print these entries and their corresponding transform set name.
'''

from ciscoconfparse import CiscoConfParse

config = CiscoConfParse('cisco_ipsec.txt')
transform_name = config.find_objects_wo_child(parentspec=r"^crypto map CRYPTO",
                                              childspec=r"set transform-set AES-SHA")

for entry in transform_name:
    print entry.text

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase {
	/**
	 * A basic test example.
	 *
	 * @return void
	 */
	public function testBasicTest () {
		$response = $this->get('/');

		$response->assertStatus(200);
	}
}


text:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<import resource="classpath:/com/francetelecom/clara/cloud/services/application-context.xml"/>

	<!-- required to configure LogicalModelCatalog -->
	<!-- this bean is used to fetch sample app properties (e.g. ear maven references) from paas-samples.properties -->
	<bean id="sampleAppProperties" class="com.francetelecom.clara.cloud.logicalmodel.samplecatalog.SampleAppProperties"/>

    <!--Change this to test against a faulty logical model catalog-->
    <bean id="echoLogicalModelCatalog" class="com.francetelecom.clara.cloud.logicalmodel.samplecatalog.EchoConsumerLogicalModelCatalog"/>

    <!-- used by LogicalModelLifecyleTest -->
    <bean id="petClinicLogicalModelCatalog" class="com.francetelecom.clara.cloud.logicalmodel.samplecatalog.PetcliniccLogicalModelCatalog"/>
</beans>


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DesignPattern
{
    public class FactoryMethod
    {

    }
}


text:
require 'elasticband/filter/and'
require 'elasticband/filter/not'
require 'elasticband/filter/query'
require 'elasticband/filter/term'
require 'elasticband/filter/terms'

module Elasticband
  class Filter
    PARSE_FILTERS = %i(only except includes)

    def to_h
      { match_all: {} }
    end

    class << self
      # Parses filter options to a Elasticsearch syntax
      #
      # #### Options
      #
      # * `only:` Filter the search results where the condition is `true`
      # * `except`: Filter the search results where the condition is `false`.
      # * `includes:` Filter the search results with a `Match` query.
      #
      # #### Examples
      # ```
      # Filter.parse(only: { status: :published })
      # => { term: { status: :published } }
      #
      # Filter.parse(except: { company: { id: 1 } })
      # => { not: { term: { status: :published } } }
      #
      # Filter.parse(includes: ['company', on: :description])
      # => { query: { match: { description: 'company' } } }
      # ```
      def parse(options = {})
        return {} if options.blank?

        filter = parse_filters(options[:only])
        filter += parse_filters(options[:except]).map { |f| Filter::Not.new(f) }
        filter += parse_includes_filter(options[:includes])
        join_filters(filter).to_h
      end

      private

      def join_filters(filters)
        filters.count > 1 ? Filter::And.new(filters) : filters.first
      end

      def parse_includes_filter(includes_options)
        return [] if includes_options.blank?

        [Filter::Query.new(Elasticband::Query.parse(*includes_options))]
      end

      def parse_filters(options)
        return [] if options.blank?

        to_dotted_notation(options).map { |attribute, value| parse_filter(attribute, value) }
      end

      def parse_filter(attribute, value)
        if value.is_a?(Enumerable)
          Filter::Terms.new(value, attribute)
        else
          Filter::Term.new(value, attribute)
        end
      end

      def to_dotted_notation(hash_params, prefix = nil, dotted_hash = {})
        hash_params.each_with_object(dotted_hash) do |(key, val), hash|
          if val.is_a?(Hash)
            to_dotted_notation(val, "#{prefix}#{key}.", hash)
          else
            hash["#{prefix}#{key}"] = val
          end
        end
      end
    end
  end
end


text:
<!DOCTYPE html>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />

    <title>{{page.title}}</title>
    {% if page.meta %}
    <meta name="description" content="{{page.title}}" />
    {% else %}
    <meta name="description" content="{{ site.meta_description}}" />
    {% endif %}

    <meta name="HandheldFriendly" content="True" />
    <meta name="MobileOptimized" content="320" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <meta name="twitter:card" content="summary" />
    <meta name="twitter:site" content="@brianstorti" />
    <meta name="twitter:creator" content="@brianstorti" />
    <meta name="og:title" content="{{page.title}}" />
    <meta name="og:image" content="http://{{site.url}}/assets/images/profile-small.png" />

    <meta name="og:description" content="{{page.title}}" />

    <link rel="stylesheet" type="text/css" href="/assets/css/master.min.css" />
    <link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Noto+Serif:400,700,400italic|Open+Sans:700,400" />
    <link rel="stylesheet" href="/assets/fontello/css/fontello.css">

    {{ content }}


text:
package org.apache.shindig.gadgets.render;

import com.google.inject.Inject;
import org.apache.shindig.common.JsonSerializer;
import org.apache.shindig.common.uri.UriBuilder;
import org.apache.shindig.gadgets.Gadget;
import org.apache.shindig.gadgets.GadgetContext;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.http.ContentFetcherFactory;
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.oauth.OAuthArguments;
import org.apache.shindig.gadgets.preload.PreloadException;
import org.apache.shindig.gadgets.preload.PreloadedData;
import org.apache.shindig.gadgets.preload.PreloaderService;
import org.apache.shindig.gadgets.preload.Preloads;
import org.apache.shindig.gadgets.rewrite.ContentRewriterRegistry;
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.View;
import org.json.JSONArray;

import java.nio.charset.Charset;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Handles producing output markup for a gadget based on the provided context.
 */
public class HtmlRenderer {
  private final ContentFetcherFactory fetcher;
  private final PreloaderService preloader;
  private final ContentRewriterRegistry rewriter;

  private static final Charset UTF8 = Charset.forName("UTF-8");
  private static final Logger logger = Logger.getLogger(HtmlRenderer.class.getName());

  @Inject
  public HtmlRenderer(ContentFetcherFactory fetcher,
                      PreloaderService preloader,
                      ContentRewriterRegistry rewriter) {
    this.fetcher = fetcher;
    this.preloader = preloader;
    this.rewriter = rewriter;
  }

  /**
   * Render the gadget into a string by performing the following steps:
   *
   * - Retrieve gadget specification information (GadgetSpec, MessageBundle, etc.)
   *
   * - Fetch any preloaded data needed to handle the request, as handled by Preloader.
   *
   * - Perform rewriting operations on the output content, handled by Rewriter.
   *
   * @param gadget The gadget for the rendering operation.
   * @return The rendered gadget content
   * @throws RenderingException if any issues arise that prevent rendering.
   */
  public String render(Gadget gadget) throws RenderingException {
    try {
      View view = gadget.getCurrentView();
      GadgetContext context = gadget.getContext();
      GadgetSpec spec = gadget.getSpec();

      Preloads preloads = preloader.preload(context, spec,
          PreloaderService.PreloadPhase.HTML_RENDER);
      gadget.setPreloads(preloads);

      String content;

      if (view.getHref() == null) {
        content = view.getContent();
      } else {
        Preloads proxyPreloads = preloader.preload(context, spec,
            PreloaderService.PreloadPhase.PROXY_FETCH);

        // TODO: Add current url to GadgetContext to support transitive proxying.
        UriBuilder uri = new UriBuilder(view.getHref());
        uri.addQueryParameter("lang", context.getLocale().getLanguage());
        uri.addQueryParameter("country", context.getLocale().getCountry());

        HttpRequest request = new HttpRequest(uri.toUri())
            .setIgnoreCache(context.getIgnoreCache())
            .setOAuthArguments(new OAuthArguments(view))
            .setAuthType(view.getAuthType())
            .setSecurityToken(context.getToken())
            .setContainer(context.getContainer())
            .setGadget(spec.getUrl());

        // POST any preloaded content
        if ((proxyPreloads != null) && !proxyPreloads.getData().isEmpty()) {
          JSONArray array = new JSONArray();

          for (PreloadedData preload : proxyPreloads.getData()) {
            try {
              Map<String, Object> dataMap = preload.toJson();
              for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
                // TODO: the existing, supported content is JSONObjects that contain the
                // key already.  Discarding the key is odd.
                array.put(entry.getValue());
              }
            } catch (PreloadException pe) {
              logger.log(Level.WARNING, "Unexpected error when preloading", pe);
            }
          }

          String postContent = JsonSerializer.serialize(array);
          // POST the preloaded content, with a method override of GET
          // to enable caching
          request.setMethod("POST")
              .addHeader("X-Method-Override", "GET")
              .setPostBody(UTF8.encode(postContent).array());
        }

        HttpResponse response = fetcher.fetch(request);
        if (response.getHttpStatusCode() != HttpResponse.SC_OK) {
          throw new RenderingException("Unable to reach remote host. HTTP status " +
              response.getHttpStatusCode());
        }

        content = response.getResponseAsString();
      }

      return rewriter.rewriteGadget(gadget, content);
    } catch (GadgetException e) {
      throw new RenderingException(e.getMessage(), e);
    }
  }
}


text:
"""
Classes representing uploaded files.
"""

import os
from io import BytesIO

from django.conf import settings
from django.core.files.base import File
from django.core.files import temp as tempfile
from django.utils.encoding import force_str

__all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile',
           'SimpleUploadedFile')

class UploadedFile(File):
    """
    A abstract uploaded file (``TemporaryUploadedFile`` and
    ``InMemoryUploadedFile`` are the built-in concrete subclasses).

    An ``UploadedFile`` object behaves somewhat like a file object and
    represents some file data that the user submitted with a form.
    """
    DEFAULT_CHUNK_SIZE = 64 * 2**10

    def __init__(self, file=None, name=None, content_type=None, size=None, charset=None, content_type_extra=None):
        super(UploadedFile, self).__init__(file, name)
        self.size = size
        self.content_type = content_type
        self.charset = charset
        self.content_type_extra = content_type_extra

    def __repr__(self):
        return force_str("<%s: %s (%s)>" % (
            self.__class__.__name__, self.name, self.content_type))

    def _get_name(self):
        return self._name

    def _set_name(self, name):
        # Sanitize the file name so that it can't be dangerous.
        if name is not None:
            # Just use the basename of the file -- anything else is dangerous.
            name = os.path.basename(name)

            # File names longer than 255 characters can cause problems on older OSes.
            if len(name) > 255:
                name, ext = os.path.splitext(name)
                ext = ext[:255]
                name = name[:255 - len(ext)] + ext

        self._name = name

    name = property(_get_name, _set_name)

class TemporaryUploadedFile(UploadedFile):
    """
    A file uploaded to a temporary location (i.e. stream-to-disk).
    """
    def __init__(self, name, content_type, size, charset, content_type_extra):
        if settings.FILE_UPLOAD_TEMP_DIR:
            file = tempfile.NamedTemporaryFile(suffix='.upload',
                dir=settings.FILE_UPLOAD_TEMP_DIR)
        else:
            file = tempfile.NamedTemporaryFile(suffix='.upload')
        super(TemporaryUploadedFile, self).__init__(file, name, content_type, size, charset, content_type_extra)

    def temporary_file_path(self):
        """
        Returns the full path of this file.
        """
        return self.file.name

    def close(self):
        try:
            return self.file.close()
        except OSError as e:
            if e.errno != 2:
                # Means the file was moved or deleted before the tempfile
                # could unlink it.  Still sets self.file.close_called and
                # calls self.file.file.close() before the exception
                raise

class InMemoryUploadedFile(UploadedFile):
    """
    A file uploaded into memory (i.e. stream-to-memory).
    """
    def __init__(self, file, field_name, name, content_type, size, charset, content_type_extra):
        super(InMemoryUploadedFile, self).__init__(file, name, content_type, size, charset, content_type_extra)
        self.field_name = field_name

    def open(self, mode=None):
        self.file.seek(0)

    def close(self):
        pass

    def chunks(self, chunk_size=None):
        self.file.seek(0)
        yield self.read()

    def multiple_chunks(self, chunk_size=None):
        # Since it's in memory, we'll never have multiple chunks.
        return False

class SimpleUploadedFile(InMemoryUploadedFile):
    """
    A simple representation of a file, which just has content, size, and a name.
    """
    def __init__(self, name, content, content_type='text/plain'):
        content = content or b''
        super(SimpleUploadedFile, self).__init__(BytesIO(content), None, name,
                                                 content_type, len(content), None, None)

    def from_dict(cls, file_dict):
        """
        Creates a SimpleUploadedFile object from
        a dictionary object with the following keys:
           - filename
           - content-type
           - content
        """
        return cls(file_dict['filename'],
                   file_dict['content'],
                   file_dict.get('content-type', 'text/plain'))
    from_dict = classmethod(from_dict)


text:
#include "tensorflow/contrib/lite/simple_memory_arena.h"

#include <algorithm>
#include <cstring>
#include <limits>
#include <vector>

namespace {

template <typename T>
T AlignTo(size_t alignment, T offset) {
  return offset % alignment == 0 ? offset
                                 : offset + (alignment - offset % alignment);
}

}  // namespace

namespace tflite {

TfLiteStatus SimpleMemoryArena::Allocate(TfLiteContext* context,
                                         size_t alignment, size_t size,
                                         ArenaAlloc* new_alloc) {
  TF_LITE_ENSURE(context, alignment <= arena_alignment_);

  if (size == 0) {
    new_alloc->offset = 0;
    new_alloc->size = 0;
    return kTfLiteOk;
  }

  size_t current_top = 0;

  if (!allocs_.empty()) {
    auto last = allocs_.rbegin();
    current_top = last->offset + last->size;
  }

  // If we don't find a better gap just allocate at the end of the buffer.
  size_t best_offset = AlignTo(alignment, current_top);
  size_t best_offset_fit = std::numeric_limits<size_t>::max();
  auto best_insertion_it = allocs_.end();

  // Go through the sorted allocs and look at the gaps between them.
  size_t current_offset = 0;
  for (auto it = allocs_.begin(); it != allocs_.end(); ++it) {
    size_t aligned_current_offset = AlignTo(alignment, current_offset);
    // If we found a gap larger than required size, and smaller than previous
    // best fit, take it.
    if (aligned_current_offset + size <= it->offset &&
        it->offset - current_offset < best_offset_fit) {
      best_offset = aligned_current_offset;
      best_offset_fit = it->offset - current_offset;
      best_insertion_it = it;
    }
    current_offset = it->offset + it->size;
  }

  // Update the required buffer size.
  high_water_mark_ = std::max(high_water_mark_, best_offset + size);

  new_alloc->offset = best_offset;
  new_alloc->size = size;
  allocs_.insert(best_insertion_it, *new_alloc);

  return kTfLiteOk;
}

TfLiteStatus SimpleMemoryArena::Deallocate(TfLiteContext* context,
                                           const ArenaAlloc& alloc) {
  if (alloc.size == 0) {
    return kTfLiteOk;
  }

  int erased_allocs_count = 0;
  auto it = allocs_.begin();
  while (it != allocs_.end()) {
    if (it->offset == alloc.offset) {
      TF_LITE_ENSURE_EQ(context, it->size, alloc.size);
      erased_allocs_count++;
      it = allocs_.erase(it);
    } else {
      ++it;
    }
  }
  TF_LITE_ENSURE_EQ(context, erased_allocs_count, 1);
  return kTfLiteOk;
}

TfLiteStatus SimpleMemoryArena::Commit(TfLiteContext* context) {
  size_t required_size = RequiredBufferSize();
  if (required_size > underlying_buffer_size_) {
    char* new_alloc = new char[required_size];
    char* new_underlying_buffer_aligned_ptr = reinterpret_cast<char*>(
        AlignTo(arena_alignment_, reinterpret_cast<intptr_t>(new_alloc)));

    // If the arena had been previously allocated, copy over the old memory.
    // Since Alloc pointers are offset based, they will remain valid in the new
    // memory block.
    if (high_water_mark_ > 0 && underlying_buffer_size_ > 0) {
      size_t copy_amount = std::min(
          underlying_buffer_.get() + underlying_buffer_size_ -
              underlying_buffer_aligned_ptr_,
          new_alloc + required_size - new_underlying_buffer_aligned_ptr);
      memcpy(new_underlying_buffer_aligned_ptr, underlying_buffer_aligned_ptr_,
             copy_amount);
    }

    underlying_buffer_.reset(new_alloc);
    underlying_buffer_size_ = required_size;
    underlying_buffer_aligned_ptr_ = new_underlying_buffer_aligned_ptr;
  }
  committed_ = true;
  return underlying_buffer_ != nullptr ? kTfLiteOk : kTfLiteError;
}

TfLiteStatus SimpleMemoryArena::ResolveAlloc(TfLiteContext* context,
                                             const ArenaAlloc& alloc,
                                             char** output_ptr) {
  TF_LITE_ENSURE(context, committed_);
  TF_LITE_ENSURE(context, output_ptr != nullptr);
  if (alloc.size == 0) {
    *output_ptr = nullptr;
  } else {
    *output_ptr = underlying_buffer_aligned_ptr_ + alloc.offset;
  }
  return kTfLiteOk;
}

TfLiteStatus SimpleMemoryArena::Clear() {
  committed_ = false;
  high_water_mark_ = 0;
  allocs_.clear();
  return kTfLiteOk;
}

}  // namespace tflite


text:
@CHARSET "UTF-8";
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h3,h4,h5,h6,pre,form,fieldset,input,
textarea,p,blockquote,th,td { margin:0;padding: 0; }
fieldset,img { border:0 }
address,caption,cite,code,dfn,em,strong,th,var { font-style:normal;
    font-weight:normal; }
ol,ul { list-style:none }
caption,th { text-align:left }
h1,h2,h3,h4,h5,h6 { font-size:100%;font-weight:normal;}
q:before,q:after { content:'' }
abbr,acronym { border:0 }

.bc{margin-left:auto;margin-right:auto;}
.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden;}
.clearfix{display:inline-block;}
* html .clearfix{height:1%;}
.tc{text-align:center;}
.fl{float:left;display:inline;}
.fr{float:right;display:inline;}
.pr{position:relative;}
.pa{position:absolute;}
.f12{ font-size: 12px;}
.f14{ font-size: 14px;}
.f15{ font-size: 15px;}
.f16{ font-size: 16px;}
.f18{ font-size: 18px;}
.f20{ font-size: 20px;}
.f24{ font-size: 24px;}
.f27{ font-size: 27px;}

.txtcut{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}
.offscreen{ position: absolute;left: -1000em}

.dn{ display: none;}
.db{ display: block;}
/*登陆界面*/
.m-login{width:395px;height:auto;position:absolute;left:50%;top:10%;margin-left:-190px}
.m-login .logo{text-align:center;}
.m-login h1.tt{text-align:center;font-size:32px;color:#434343;font-family:"Micorsoft YaHei",微软雅黑;font-weight:normal;margin-top:62px;margin-bottom:60px;}
.m-login .loginForm{display:block;width:100%;}
.m-login .loginForm .fom-item{height:50px;width:395px;padding-bottom:22px;}
.m-login input.log, .m-login input.pwd{ height:20px;padding-top:14px;padding-bottom:14px;border:1px solid #E2E2E2;width:353px; line-height:20px;padding-left:45px;border-radius:3px;font-size:16px;color:#000;}
.m-login input.log{background:url(../images/icon-log-pwd.png) no-repeat 10px top scroll #ffffff;}
.m-login input.pwd{background:url(../images/icon-log-pwd.png) no-repeat 10px bottom scroll #ffffff;}
.m-login input.sub{height:46px;width:398px;background-color:#207CD1; line-height:46px;border-radius:3px;text-align:center;color:#ffffff;font-size:14px;cursor:pointer;border:0;}
.m-login .copy{text-align:center;color:#A9A9A9;font-size:12px;margin-top:110px;}
.s-bg-f9{background-color:#f9f9f9}
.loginForm .error{color:#D20A2F;font-size:12px;margin-left:10px;display:block;height:42px;line-height: 42px;}
.m-login input.log:-ms-input-placeholder, .m-login input.pwd:-ms-input-placeholder { /* Internet Explorer 10+ */color:#999;}