ASPxClientHiddenField = _aspxCreateClass(ASPxClientControl, {
 constructor: function(name) {
  this.constructor.prototype.constructor.call(this, name);
  this.syncWithServer = true;
  this.properties = { };
  this.typeInfoTable = { };
  this.typeNameTable = [ ];
  this.allowMultipleCallbacks = false;
  this.serializer = _aspxGetHiddenFieldSerializer();
 },
 InlineInitialize: function() {
  if(this.syncWithServer) {
   var postHandler = aspxGetPostHandler();
   postHandler.Post.AddHandler(this.OnPost, this);
  }
 },
 GetInputElement: function() {
  if(this.inputElement == null)
   this.inputElement = document.getElementById(this.name + ASPxClientHiddenField.InputElementIDSuffix);
  return this.inputElement;
 },
 OnPost: function() {
  var inputElement = this.GetInputElement();
  if(_aspxIsExists(inputElement)) {
   var serializedData = this.serializer.Serialize(this);
   inputElement.value = _aspxEncodeHtml(serializedData);
  }
 },
 PerformCallback: function(parameter) {
  this.CreateCallback(parameter);
 },
 OnCallback: function(result) {
  var callbackMarkupContainer = this.GetCallbackMarkupContainer();
  _aspxSetInnerHtml(callbackMarkupContainer, result);
 },
 GetCallbackMarkupContainer: function() {
  var callbackMarkupContainer = _aspxGetElementById(this.GetCallbackMarkupContainerID());
  if(!_aspxIsExists(callbackMarkupContainer)) {
   callbackMarkupContainer = this.CreateCallbackMarkupContainer();
   document.body.appendChild(callbackMarkupContainer);
  }
  return callbackMarkupContainer;
 },
 GetCallbackMarkupContainerID: function() {
  return this.name + ASPxClientHiddenField.CallbackMarkupContainerIDSuffix;
 },
 CreateCallbackMarkupContainer: function() {
  var callbackMarkupContainer = document.createElement("DIV");
  _aspxSetElementDisplay(callbackMarkupContainer, false);
  callbackMarkupContainer.id = this.GetCallbackMarkupContainerID();
  return callbackMarkupContainer;
 },
 Add: function(propertyName, propertyValue) {
  var existentPropertyValue = this.Get(propertyName);
  if(typeof(existentPropertyValue) == "undefined")
   this.Set(propertyName, propertyValue);
  else
   alert("A property with the name '" + propertyName + "' has already been added.");
 },
 Get: function(propertyName) {
  var safeName = this.GetTopLevelPropertySafeName(propertyName);
  return this.properties[safeName];
 },
 Set: function(propertyName, propertyValue) {
  var safeName = this.GetTopLevelPropertySafeName(propertyName);
  if(typeof(propertyValue) == "undefined")
   this.Remove(propertyName);
  else
   this.properties[safeName] = propertyValue;
 },
 Remove: function(propertyName) {
  var safeName = this.GetTopLevelPropertySafeName(propertyName);
  delete this.properties[safeName];
  this.serializer.typeInfoHelper.RemoveTypeInfoBranch(this.typeInfoTable, safeName);
 },
 Clear: function() {
  this.properties = { };
  this.typeInfoTable = { };
  this.typeNameTable = [ ];
 },
 Contains: function(propertyName) {
  var safeTopLevelPropertyName = this.GetTopLevelPropertySafeName(propertyName);
  for(var key in this.properties) {
   if(key == safeTopLevelPropertyName)
    return true;
  }
  return false;
 },
 GetTopLevelPropertySafeName: function(propertyName) {
  return ASPxClientHiddenField.TopLevelKeyPrefix + propertyName;
 }
});
ASPxClientHiddenField.InputElementIDSuffix = "_I";
ASPxClientHiddenField.CallbackMarkupContainerIDSuffix = "_D";
ASPxClientHiddenField.TopLevelKeyPrefix = "dxp";
ASPxTypeInfoHelper = _aspxCreateClass(null, {
 constructor: function() {
  this.minUnknownTypeIndex = 1024;
  this.clientTypeConstructors = [
   null,
   Number,
   String,
   Date,
   Boolean,
   RegExp,
   Array,
   Object
  ];
  this.clientTypeConstructorIndices = { };
  for(var i = 1; i < this.clientTypeConstructors.length; i++)
   this.clientTypeConstructorIndices[this.clientTypeConstructors[i]] = i;
 },
 EnsureTypeInfoTableCompliant: function(value, typeInfoTable, typeInfoKey) {
  if(typeInfoKey == "")
   return;
  var typeCode = typeInfoTable[typeInfoKey];
  if(typeof(typeCode) != "undefined") {
   if(!this.IsValueTypeInfoCompliant(value, typeCode))
    this.RemoveTypeInfoBranch(typeInfoTable, typeInfoKey);
   else
    return;
  }
  typeCode = this.CreateTypeCode(value);
  if(typeof(typeCode) != "undefined")
   typeInfoTable[typeInfoKey] = typeCode;
  else
   delete typeInfoTable[typeInfoKey];
 },
 IsAtomValue: function(value, typeCode) {
  return typeCode == 0 || !(this.IsListValue(value, typeCode) || this.IsDictionaryValue(value, typeCode));
 },
 IsListValue: function(value, typeCode) {
  return this.IsKnownTypeCode(typeCode) ? this.GetConstructor(typeCode) === Array : value.constructor === Array;
 },
 IsDictionaryValue: function(value, typeCode) {
  return this.IsKnownTypeCode(typeCode) ? this.GetConstructor(typeCode) === Object : value.constructor === Object;
 },
 GetArrayTypeCode: function() {
  return this.clientTypeConstructorIndices[Array] << 1;
 },
 GetStringTypeCode: function() {
  return this.clientTypeConstructorIndices[String] << 1;
 },
 IsStringTypeCode: function(typeCode) {
  return typeCode == this.GetStringTypeCode();
 },
 IsValueTypeInfoCompliant: function(value, typeCode) {
  if(this.IsKnownTypeCode(typeCode))
   return value != null ? value.constructor === this.GetConstructor(typeCode) : this.IsNullable(typeCode);
  else
   return value == null || value.constructor === Array || value.constructor === Object;
 },
 CreateTypeCode: function(value) {
  if(value == null)
   return 1; 
  var clientTypeIndex = this.clientTypeConstructorIndices[value.constructor];
  var lowerBit = Number(
   clientTypeIndex == this.clientTypeConstructorIndices[RegExp] ||
   clientTypeIndex == this.clientTypeConstructorIndices[Array] ||
   clientTypeIndex == this.clientTypeConstructorIndices[Object]
  );
  return typeof(clientTypeIndex) != "undefined" ? ((clientTypeIndex << 1) + lowerBit) : void(0);
 },
 IsNullable: function(typeCode) {
  return (typeCode & 1) > 0;
 },
 GetConstructor: function(typeCode) {
  return this.clientTypeConstructors[(typeCode >>> 1) & 7];
 },
 IsKnownTypeCode: function(typeCode) {
  return typeCode < this.minUnknownTypeIndex;
 },
 RemoveTypeInfoBranch: function(typeInfoTable, typeInfoKeyPrefix) {
  for(var key in typeInfoTable) {
   if(key.indexOf(typeInfoKeyPrefix) == 0)
    delete typeInfoTable[key];
  }
 }
});
ASPxHiddenFieldSerializer = _aspxCreateClass(null, {
 constructor: function() {
  this.typeInfoHelper = new ASPxTypeInfoHelper();
  this.separator = "|";
  this.sentinel = "#";
  this.charCodes = this.CreateCharCodeList([ "a", "z", "0", "9", "_", "$" ]);
 },
 Serialize: function(hiddenField) {
  var sb = new ASPxStringBuilder();
  this.SerializeCore(hiddenField.typeNameTable, "", sb, null, null, null, false);
  this.SerializeCore(hiddenField.properties, "", sb, hiddenField.typeInfoTable, hiddenField.typeNameTable, ASPxClientHiddenField.TopLevelKeyPrefix, true);
  return sb.ToString();
 },
 SerializeCore: function(value, pathInPropertiesTree, serializedData, typeInfoTable, typeNameTable, keyNamePrefix, validateKeys) {
  var metaTablesDefined = typeInfoTable != null && typeNameTable != null;
  var typeCode = null;
  if(metaTablesDefined) {
   this.typeInfoHelper.EnsureTypeInfoTableCompliant(value, typeInfoTable, pathInPropertiesTree);
   typeCode = typeInfoTable[pathInPropertiesTree];
  } else {
   typeCode = value.constructor === Array ?
    this.typeInfoHelper.GetArrayTypeCode() : this.typeInfoHelper.GetStringTypeCode();
  }
  if(typeof(typeCode) != "undefined")
   serializedData.Append(typeCode);
  serializedData.Append(this.separator);
  if(typeof(typeCode) == "undefined" || this.typeInfoHelper.IsDictionaryValue(value, typeCode)) {
   for(var key in value) {
    var serializableKey = key;
    if(keyNamePrefix.length > 0)
     serializableKey = serializableKey.slice(keyNamePrefix.length);
    if(validateKeys)
     this.AssertKeyIsValid(serializableKey);
    serializedData.Append(serializableKey);
    serializedData.Append(this.separator);
    this.SerializeCore(value[key], pathInPropertiesTree.length > 0 ? (pathInPropertiesTree + this.separator + key) : key,
     serializedData, typeInfoTable, typeNameTable, "", validateKeys);   
   }
   serializedData.Append(this.sentinel);
  } else if(this.typeInfoHelper.IsListValue(value, typeCode)) {
   for(var i = 0; i < value.length; i++)
    this.SerializeCore(value[i], pathInPropertiesTree.length > 0 ? (pathInPropertiesTree + this.separator + i) : i,
     serializedData, typeInfoTable, typeNameTable, "", validateKeys);
   serializedData.Append(this.sentinel);
  } else if(this.typeInfoHelper.IsAtomValue(value, typeCode))
   this.SerializeAtomValue(value, serializedData, typeCode);
 },
 SerializeAtomValue: function(value, sb, typeCode) {
  var valueStr = this.SerializeAtomValueCore(value, typeCode);
  sb.Append(valueStr.length.toString());
  sb.Append(this.separator);
  sb.Append(valueStr);
 },
 SerializeAtomValueCore: function(value, typeCode) {
  var isString = this.typeInfoHelper.IsStringTypeCode(typeCode);
  if(value == null)
   return isString ? "0" : "";
  else {
   if(isString)
    return "1" + value;
   else {
    var ctor = value.constructor;
    if(ctor === String )
     return value;
    else if(ctor === Boolean)
     return value ? "1" : "0";
    else if(ctor === Number)
     return value.toString();
    else if(ctor === Date)
     return String(_aspxToLocalTime(value).valueOf());
    else if(ctor === RegExp) {
     var options = "";
     if(value.ignoreCase)
      options += "i";
     if(value.multiline)
      options += "m";
     return options + "," + value.source;
    }
   }
  }
  alert("Unable to serialize value " + value.toString() + " (Constructor: " + value.constructor.toString() + ").");
 },
 AssertKeyIsValid: function(key) {
  if(!key)
   alert("Empty key.");
  else {
   key = key.toLowerCase();
   var code = key.charCodeAt(0);
   if(!(this.IsLowercaseLetterCharCode(code) || code == this.charCodes["_"] || code == this.charCodes["$"]))
    alert("Invalid key '" + key + "'.");
   for(var i = 1; i < key.length; i++) {
    code = key.charCodeAt(i);
    if(!(this.IsLowercaseLetterOrDigitCharCode(code) || code == this.charCodes["_"] || code == this.charCodes["$"]))
     alert("Invalid key '" + key + "'.");
   }
  }
 },
 CreateCharCodeList: function(chars) {
  var charCodes = { };
  for(var i = 0; i < chars.length; i++) {
   var ch = chars[i];
   charCodes[ch] = ch.charCodeAt(0);
  }
  return charCodes;
 },
 IsLowercaseLetterCharCode: function(charCode) {
  return charCode >= this.charCodes["a"] && charCode <= this.charCodes["z"];
 },
 IsLowercaseLetterOrDigitCharCode: function(charCode) {
  if(this.IsLowercaseLetterCharCode(charCode))
   return true;
  else
   return charCode >= this.charCodes["0"] && charCode <= this.charCodes["9"];
 }
});
function _aspxGetHiddenFieldSerializer() {
 if(!window.__aspxHiddenFieldSerializer)
  window.__aspxHiddenFieldSerializer = new ASPxHiddenFieldSerializer();
 return window.__aspxHiddenFieldSerializer;
}
