function clone (o, append) {
  if(o == null || typeof(o) != 'object')
	return o;	  
	  
  var objectClone = new o.constructor();	  
  for (var property in o)
	if (typeof this[property] == 'object')
	  objectClone[property] = clone(o[property]);
	else
	  objectClone[property] = o[property];

  for (var i in append){
  	objectClone[i] = append[i];
  }

  return objectClone;
}

function stringBytesUTF8(s) {
	// returns the php lenght of a string (bytes, not chars)
	var 	c, b = 0,
		l = s.length;
	while(l) {
		c = s.charCodeAt(--l);
		b += (c < 128) ? 1 : ((c < 2048) ? 2 : ((c < 65536) ? 3 : 4));
	};
	return b;
}

function serializeString(s) {
	s=s.replace(/\\/g, "\\\\");
	s=s.replace(/\"/g, "\\\"");
	s=s.replace(/\n/g, "\\n");
	s=s.replace(/\r/g, "");

	return 's:' + s.length + ':"' + s + '";';
}

function serializeObject(o) {
	var php = '';
	var total = 0;
	for (var key in o) {
		++ total;
		// Key
		php += serializeString(key.toString());
		php += serialize(o[key]);
	}

	return "a:" + total + ":{" + php + "}";
}

function serializeArray(o) {
	var php = '';
	var total = 0;
	for (var key = 0; key < o.length; key++) {
		total++;
		// Key
		php += 'i:' + key + ';';
		php += serialize(o[key]);
	}

	return "a:" + total + ":{" + php + "}";
}

function serialize(o){
	if(o.constructor == Object)
		return serializeObject(o);
	else if(o.constructor == Array)
		return serializeArray(o);
	else
		return serializeString(o.toString());
}

function serializePHP (mixed_value) {
	// http://kevin.vanzonneveld.net
	// +   original by: Arpad Ray (mailto:arpad@php.net)
	// +   improved by: Dino
	// +   bugfixed by: Andrej Pavlovic
	// +   bugfixed by: Garagoth
	// +	  input by: DtTvB (http://dt.in.th/2008-09-16.string-length-in-bytes.html)
	// +   bugfixed by: Russell Walker (http://www.nbill.co.uk/)
	// +   bugfixed by: Jamie Beck (http://www.terabit.ca/)
	// +	  input by: Martin (http://www.erlenwiese.de/)
	// +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	// -	depends on: utf8_encode
	// %		  note: We feel the main purpose of this function should be to ease the transport of data between php & js
	// %		  note: Aiming for PHP-compatibility, we have to translate objects to arrays
	// *	 example 1: serialize(['Kevin', 'van', 'Zonneveld']);
	// *	 returns 1: 'a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}'
	// *	 example 2: serialize({firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'});
	// *	 returns 2: 'a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}'
	var _getType = function (inp) {
		var type = typeof inp, match;
		var key;
		if (type == 'object' && !inp) {
			return 'null';
		}
		if (type == "object") {
			if (!inp.constructor) {
				return 'object';
			}
			var cons = inp.constructor.toString();
			match = cons.match(/(\w+)\(/);
			if (match) {
				cons = match[1].toLowerCase();
			}
			var types = ["boolean", "number", "string", "array"];
			for (key in types) {
				if (cons == types[key]) {
					type = types[key];
					break;
				}
			}
		}
		return type;
	};
	var type = _getType(mixed_value);
	var val, ktype = '';
	
	switch (type) {
		case "function": 
			val = ""; 
			break;
		case "boolean":
			val = "b:" + (mixed_value ? "1" : "0");
			break;
		case "number":
			val = (Math.round(mixed_value) == mixed_value ? "i" : "d") + ":" + mixed_value;
			break;
		case "string":
			//val = "s:" + encodeURIComponent(mixed_value).replace(/%../g, 'x').length + ":\"" + mixed_value + "\"";
			mixed_value = mixed_value.replace(/\\/g, "\\\\");
			mixed_value = mixed_value.replace(/\"/g, "\\\"");
			mixed_value = mixed_value.replace(/\n/g, "\\n");
			mixed_value = mixed_value.replace(/\r/g, "");
			
			val = "s:" + mixed_value.length + ":\"" + mixed_value + "\"";
        
			break;
		case "array":
		case "object":
			val = "a";
			var count = 0;
			var vals = "";
			var okey;
			var key;
			for (key in mixed_value) {
				ktype = _getType(mixed_value[key]);
				if (ktype == "function") { 
					continue; 
				}
				
				okey = (key.match(/^[0-9]+$/) ? parseInt(key, 10) : key);
				vals += this.serializePHP(okey) +
						this.serializePHP(mixed_value[key]);
				count++;
			}
			val += ":" + count + ":{" + vals + "}";
			break;
		case "undefined": // Fall-through
		default: // if the JS object has a property which contains a null value, the string cannot be unserialized by PHP
			val = "N";
			break;
	}
	if (type != "object" && type != "array") {
		val += ";";
	}
	return val;
}