/*! بسم الله الرحمان الرحيم
 * Proto Javascript Library V0.1
 *

 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 * Copyright 2011, The Dojo Foundation
 * Released under the MIT, BSD, and GPL Licenses.
 *
 * Date: Mon Jan 31 08:31:29 2011 -0500
 */



(function(){
	
	// save a reference to some core objects and methods
	
	    var global            = window,
		    Object            = global.Object,
			Array             = global.Array,
			Function          = global.Function,
			String            = global.String,
			Number            = global.Number,
			Date              = global.Date,
			RegExp            = global.RegExp,
			Math              = global.Math,
			objectPrototype   = Object.prototype,
			arrayPrototype    = Array.prototype,
			functionPrototype = Function.prototype,
			stringPrototype   = String.prototype,
			numberPrototype   = Number.prototype,
			datePrototype     = Date.prototype,
			regExpPrototype   = RegExp.prototype,
			hasOwnProperty    = objectPrototype.hasOwnProperty,
			toString          = objectPrototype.toString,
			slice             = arrayPrototype.slice,
			concat            = arrayPrototype.concat,
			isNaN             = global.isNaN,
			isFinite          = global.isFinite,
			createObject      = function(){},
			setTimeOut        = global.setTimeout,
			clearTimeOut      = global.clearTimeout,
			setInterval       = global.setInterval,
			clearInterval     = global.clearInterval,
			proto;
			
  			
			
	function isFunction(fun){
		   
		  return toString.call(fun) === "[object Function]";
	   }
	   
	   
	function isArray(array){
		   
		   return toString.call(array) === "[object Array]";
	   }
	   
	   
	function  isString(string){
		   
		   return typeof string === "string";   
	   }
	   
		
		
	function isNull(data){
			
			return data === null;
		}
		
		
		
	function isNumber(number){
			
			return typeof number === "number" && !isNaN(number) && isFinite(number);
		}
		
		
	function isRegExp(obj){
		
		return toString.call(obj) === "[object RegExp]";
		
		}
		
	function isPlainObject( obj ) {
		// Must be an Object.
		// Because of IE, we also have to check the presence of the constructor property.
		// Make sure that DOM nodes and window objects don't pass through, as well
		if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
			return false;
		}
		
		// Not own constructor property must be Object
		if ( obj.constructor
			&& !hasOwnProperty.call(obj, "constructor")
			&& !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
			return false;
		}
		
		// Own properties are enumerated firstly, so to speed up,
		// if last one is own, then all properties are own.
	
		var key;
		for ( key in obj ) {}
		
		return key === undefined || hasOwnProperty.call( obj, key );
	}
		
		
   function isElement(element){
		
		return isObject(element) && element.nodeType === 1;
		
		}
		
		
		
   function isTextNode(text){
		
		return isObject(text) && text.nodeType === 3;
		
		}
		
		
		
		
		var object = (function(){
			
				   
		     function fakeConstructor(){};
			 
			 
				
				
		function create(proto,props){
					
			if( Object.create ){
				 
				 return Object.create( proto, props);	
				 		 
			 };

			  var proto = typeof proto == "object" ? proto : null;
			  
			  if( Object.__proto__ ){
				  
				  var obj = {};
				  
				  obj.__proto__ = proto;
				  
			  }else{
				  			  var obj       = createObject;
			                  obj.prototype = proto;
							  obj           = new obj();
			  };
			  
			    if(typeof props == "object"){
					
				  this.each(props,function(value,key){
			
					  if(isPlainObject( props[ key ] )){
					 
					 obj[ key ] = value.value;
					 
					  }
					  
				  });
				  
				  };
				  
				  return obj;
			  
			  
		 
				}
				
				function extend(){
					
			 var objs   = slice.call(arguments),
			     obj    = objs.shift(),
			     length = objs.length,
			     deep   = typeof objs[length-1]=="boolean"?objs.pop():false;
				 
			 for(var i = 0; i<length ;i += 1){
				 var ob = objs[i];
			 this.each(ob,function(value,prop){
								  obj[prop]=value;
								  },obj,deep)
			 }
			 
			      return obj;
					
				}
				
				function each( object , callback , context , deep ){
		  
		  var context = typeof context == "object" ? context : null ;
		  
		  if(!deep){
			  
			  for( var prop in object){
				  
				  if( hasOwnProperty.call(object,prop) ){
					  
					  callback.call(context , object[prop] , prop , object );
					  
				  };
			  };
			  
			  return this;
			  
		  };
		  
		  			  for( var prop in object){
				
					  callback.call(context , object[prop] , prop , object);  
			  };
			  
			  return this;
	  
		  }
		  
		   function keys(object){
			   
			   if( hasOwnProperty.call(Object,"keys") ){
				   
				   return Object.keys(object);
	   
			   }
			   
			 var keys = [],
			     i    = 0;
			 
			 for( var key in object){
				 
				 if(hasOwnProperty.call(object,key)){
					 
					 keys[i] = key;
					 
					 i += 1;
				 }
			 }
			 
			 
			 return keys;
		 }
		 
		 
		 function values(object){
			 
			   if( hasOwnProperty.call(Object,"values") ){
				   
				   return Object.values(object);
	   
			   }
			 
			var values = [],
			    i      = 0;
			 
			 for( var value in object){
				 
				 if(hasOwnProperty.call(object,value)){
					 
					 values[i] = object[value];
					 
					 i += 1;
				 }
			 }
			 
			 return values;
		 }
		 
		 
		 function defineProperty(object,prop,discriptor){
			 
			 hasOwnProperty.call(Object,"defineProperty") ? 
			  
			                     Object.defineProperty(object,prop,discriptor) : object[prop] = discriptor.value;
			 
		 }
		 
		 
		 function seal(object){
			 
			 return  hasOwnProperty.call(Object,"seal") ?  Object.seal(object) : false;	 
			 
		 }
		 
		 function isSealed(object){
			 
			  return  hasOwnProperty.call(Object,"isSealed") ?  Object.isSealed(object) : false;

		 }
		 

		 
		 function freeze(object){
			 
              return  hasOwnProperty.call(Object,"freeze") ?  Object.freeze(object) : false;
		 }
		 
		function isFrozen(object){
			 
             return  hasOwnProperty.call(Object,"isFrozen") ?  Object.isFrozen(object) : false;
			  
		 }
		 
		 
		 
		function preventExtensions(object){
			 
           return  hasOwnProperty.call(Object,"preventExtensions") ?  Object.preventExtensions(object) : false;
			  
		 }
		 
		 
	 
	 	function isExtensible(object){
			 
           return  hasOwnProperty.call(Object,"isExtensible") ?  Object.isExtensible(object) : false;
			  
		 }
		 

		  
		  
		  return {
			  
			  create            : create,
			  defineProperty    : defineProperty,
			  extend            : extend,
			  keys              : keys,
			  values            : values,
			  each              : each,
			  seal              : seal,
			  isSealed          : isSealed,
			  freeze            : freeze,

			  isFrozen          : isFrozen,
			  preventExtensions : preventExtensions,
			  isExtensible      : isExtensible
			  
			  
		  }
		  		
			}());	
		
		
		
		var fun = (function(){
		
		
		function curry(){
			
			var args = slice.call(arguments),
			    fun  = args.shift();
				
			return function(){
				
				args = concat.call(args,slice.call(arguments));
				
				return fun.apply(null,args);
				
			};
		}
		
		
		
		function bind(){
			
				var args = slice.call(arguments),
			 fun  = args.shift(),
			 obj  = args.shift();
			 
	 
			return function(){
	
				return fun.apply(obj,args);
				
			};
		}
		
		function defer(){
			
		 var args = slice.call(arguments),
			 fun  = args.shift();
			 
			 return setTimeout(function(){
				 
				 fun.apply(null,args);
			 },0);
			
			
		}
		
		function delay(){
			
					 var args = slice.call(arguments),
			            fun  = args.shift(),
						timeout = args.shift();
						
						return setTimeout(function(){
				
				 fun.apply(null,args);
			 },(timeout / 1000));  
			
		}
		
		return {
			
			curry : curry,
			bind  : bind,
			delay : delay,
			defer : defer
		}
		
		}());
		
		
		var number = (function(){
				
			function isNumber(number){
			
			return typeof number === "number" && !isNaN(number) && isFinite(number);
		}
		
		  function round(number){
			  
			  return  Math.round(number);
		  }
		 
				
				
				
				
			}());
			
			function extendNativePrototype(proto,props){
				
				var p = object.each(props,function(value,key){
					
					if(!hasOwnProperty.call(this,key)){
						
						this[key] = value;
						
					}
				},proto);
				
			}
			
		
		

		
		var numTools = (function(){
			
			var float = /^\d+.\d+$/,
			    int   = /^\d+$/;
				
				function isFloat(num){
					
					return float.test(num);
				}
				
				function isInt(num){
					
					return int.test(num);
				}
				
				return {
					isFloat : isFloat,
					isInt   : isInt
				}
			
			
		}());
		
		
/*
*
*
*
*
*/	
		
		var arrayExtra = (function(){
			
			
			var forEach = ( hasOwnProperty.call(arrayPrototype , "forEach" ) ? 
			
			  function(array,callback,thisObject){
				  
				
				  return arrayPrototype.forEach.call(array,callback,thisObject);
			  } :
			 function(array,callback,thisObject){
				 
				  var length = array.length,
			       index  = 0;
			
				   
				   while(index < length){
					   
					   callback.call(thisObject,array[index],index,array);
					   
	
					   
					   index += 1;
				   }
				   
	
				
			}), 
			
			 first = function(array){
				
				return array[0];	
			},
			   last = function(array){
				
				return array[array.length - 1];
			},
			
			 indexOf = ( hasOwnProperty.call(arrayPrototype,"indexOf") ? 
			  function(array,element,from){
				  
				  return arrayPrototype.indexOf.call(array,element,from);
			  } :
			 function(array,element,from){
				 
				  var length = array.length,
			       index  = from > -1 && from < length ? from : 0,
				   currentElement;
				   
				   while(index < length){
					   
					   currentElement = array[index];
					   
					   if(currentElement === element){
						   
						   return index;
					   }
					   
					   index += 1;
				   }
				   
				   return -1;	
				
			}),
			
			lastIndexOf = ( hasOwnProperty.call(arrayPrototype,"lastIndexOf") ?
			
			function(array, element, from){
				
				 return arrayPrototype.lastIndexOf.call(array,element,from);
			} :
			
			function(array, element, from){
				
			   var length = array.length,
			       index  = from > -1 && from < length ?  from : length,
				   currentElement;
				
				   while(index >= 0){
					   
					   currentElement = array[index];
					   
					   if(currentElement === element){
						
						   return index;
					   }
					    
					   index -= 1;
				   }
				   
				   return -1;
		   }),
		   
		   some = ( hasOwnProperty.call(arrayPrototype,"some")?
		   
		     function(array,callback,context){
				 
		
				 
				 return arrayPrototype.some.call(array,callback,context);
			 }:
		   
		   function(array,callback,context){
			   
			   var length  = array.length,
			       index   = 0,
			       context = context ? context : null,
				   element   = null;
				   
				   while(index < length){
					  
					   element = array[index];
					   
			
					   
					   if(typeof element !== "undefined" && callback.call(context,element,index,array)){
						   
						   return true;
					   }
					   
					   index += 1;
				   }
				   
				   return false;
		   }),
		   
		  every = ( hasOwnProperty.call(arrayPrototype,"every")?
		   
		     function(array,callback,context){

				 return arrayPrototype.every.call(array,callback,context);
			 }:
		   
		   function(array,callback,context){
			   
			   var length  = array.length,
			       index   = 0,
			       context = context ? context : null,
				   element = null,
				   result  = false;
				   
				   while(index < length){
					  
					   element = array[index];
					   
			
					   
					   if(typeof element !== "undefined"){
						   
						  result =  callback.call(context,element,index,array);
					   }
					   
					   index += 1;
				   }
				   
				   return result;
		   }),
		   
		   filter = ( hasOwnProperty.call(arrayPrototype,"filter") ?
		   
				   function(array,callback,context){
 
				 return arrayPrototype.filter.call(array,callback,context);
			 }:
		   
		   function(array,callback,context){
			   
			   var length  = array.length,
			       index   = 0,
			       context = context ? context : null,
				   element = null,
				   arr     = [];
				   
				   while(index < length){
					  
					   element = array[index];
					   
			
					   
					   if(typeof element !== "undefined" && callback.call(context,element,index,array)){
						   
						  arr.push(element);
					   }
					   
					   index += 1;
				   }
				   
				   return arr;
		    }),
			
			map = ( hasOwnProperty.call(arrayPrototype,"map") ?
		   
				   function(array,callback,context){
 
				 return arrayPrototype.map.call(array,callback,context);
			 }:
			 
			 function(array,callback,context){
			   
			   var length  = array.length,
			       index   = 0,
			       context = context ? context : null,
				   element = null,
				   arr     = [];
				   
				   while(index < length){
					  
					   element = array[index];
					   
			
					   
					   if(typeof element !== "undefined"){
						   
						  arr.push(callback.call(context,element,index,array));
					   }
					   
					   index += 1;
				   }
				   
				   return arr;
		    }),
			reject = function(array,callback,context){
				
				return filter(array,function(element,index){
					
					return !callback.call(context,element,index,array)
				});
			},
			find = function(array,callback,conext){
			   
			   var length  = array.length,
			       index   = 0,
			       context = context ? context : null,
				   element = null,
				   arr     = [];
				   
				   while(index < length){
					  
					   element = array[index];
					   
			
					   
					   if(typeof element !== "undefined" && callback.call(context,element,index,array)){
						   
						 return element;
					   }
					   
					   index += 1;
				   }
				   
				   return null;
		    },
			grep = function(array,pattern){
				
				return filter(array,function(element,index){
					
					return pattern.test(element);
				});
				
				
			}
		   
		   
		   reduce = function(array,callback,initialValue){
			   
			   var length         =  array.length,
			       index          = initialValue ? 0 : 1 ,
				   previousValue  = initialValue ? initialValue : array[0]
				   currentValue   = initialValue ? array[0] : array[1],
				   result         = callback.call(null, previousValue, currentValue, index, array);
				   index += 1;
				   previousValue  = array[index -2];
			       currentValue   = array[index];
   				  
				  while(index < length){
					    
			  result        += callback.call(null,previousValue,currentValue,index,array);
			  previousValue  = array[index]
			  currentValue   = array[index + 1]; 
					 index += 1; 
					  
				  }
				  
				  return result;
				   
			       
			   
			   
		   }
		   
			
	   
		   return {
			   forEach      : forEach,
			   first        : first,
			   last         : last,
			   some         : some,
			   every        : every,
			   filter       : filter,
			   reject       : reject,
			   map          : map,
			   find         : find,
			   grep         : grep,
			   indexOf      : indexOf,
			   reduce       : reduce,
			   lastIndexOf  : lastIndexOf
		   }
			
			

	   
		}());
		
		

		
		
/*	
		var queryString = (function(){
			
			var encodeURI    = global.encodeURI,
			    specialChars = /~,!,\(,\),',\%20/g,
				table        = {
		"~"  : "%7E",
		"!"  : "%21",
		"\(" : "%28",
		"\)" : "%29",  
		"'"  : "%27",
		"%20":"+"
	};
	
	function encodeString(string){
		
			return encodeURI(string).replace(specialChars,function(a,b){
														  return table[a];	
			});
		
	}

	function encodeObject(name,obj,isSubKey){
		
		var encodedObject = [],
		    isSubKey      = isSubkey ? true : false;
		
		
		object.each(obj,function(value,key){
			
			
			
			
		}
		

	}
	
	function encodeArray(name,array){
		
		var key,value,name = arguments.length == 2 && arguments[1].length ? name : "";
		
		return arrayExtra.map(array,function(elem,index){
			
			if(isPlainObject){
				
				return encodeObject(index,elem);
				
				
			}
			else{
			
			key   = encodeString(name) + "[" + key + "]";
			value = encodeString(value);
			
			return key + "=" + value;
			
			}
			
			return "";
			
			
			
			
		}).join("&");
		
		
	}
	
	

	
	
	function encode(obj){
		
		var value,
		    encodedString = [];
		
		for(var key in obj){
			
			value = obj[key];
			
			if(hasOwnProperty.call(obj,key)){
				
			
				
				if(isObject(value) && !isArray(value)){
					
					 encodedString.push(encodeObject(key,value));
				}
				else if(isArray(value)){
					
					 encodedString.push(encodeArray(key,value));
					
				}else{
				
					encodedString.push(encodeString(key) + "=" +  encodeString(value));
					
					
				}
				
				
			}
		}
		
		return encodedString.join("&");
	}
	

	return {
		encode : encode
	}
		
		
			
			
		}());
		

	*/	
	
	var Deferred = object.create( {} ,(function(){
		
		
		
		function addCallback( callbacks ){
			
			
			
			if( isArray( callbacks ) ){
				
				arrayExtra.forEach(  callbacks , function( fun , index ){
					
					if( isFunction( fun ) ){
					
					this.callbacksQueue.push( fun );
					
					}
					
				}, this );
				
				return this;
			}
			
			if( isFunction( callbacks ) ){
				
				this.callbacksQueue.push( callbacks );
			}
			
		   return this;
			
			
		}
		
		
		
		function addErrback( callbacks ){
			
			
			
			if( isArray( callbacks ) ){
				
				arrayExtra.forEach(  callbacks , function( fun , index ){
					
					if( isFunction( fun ) ){
					
					this.errbacksQueue.push( fun );
					
					}
					
				}, this );
				
				return this;
			}
			
			if( isFunction( callbacks ) ){
				
				this.errbacksQueue.push( callbacks );
			}
			
		   return this;
			
			
		}
		
				function addBoth( callback , errback ){
					
					this.addCallback( callback );
					this.addErrback( errback );
			
			
		}
		
	
		
			function fulfillWith( context , args ){
				
				
						
				arrayExtra.forEach(  this.callbacksQueue , function( fun , index ){

				
				fun.apply( context , args );

					
				}, this );
				
			
			//object.defineProperty( this , "isFulfilled" , { value : true , configurable : false , writable : false });
			
			this.isFulfilled = true;	

			return this;
			
		}
		
			function unfulfillWith( context , args ){
				
				
						
				arrayExtra.forEach(  this.errbacksQueue , function( fun , index ){

					
				fun.apply( context , args );

					
				}, this );
				
				
		//object.defineProperty( this , "isFulfilled" , { value : false , configurable : false , writable : false });
		
		this.isFulfilled = false;
				
			
			return this;
			
		}
		
		
		function fulfill(){
			
			this.fulfillWith( this , [ this ] );
			
			return this;
		}
		
		
		
		
		
		function unfulfill(){
			
			this.unfulfillWith( this , [ this ] );
			
			return this;
		}
		
		
		
		
		
		return {
			
			callbacksQueue : { value : [] , configurable : false , writable : false },
			errbacksQueue  : { value : [] , configurable : false , writable : false },
			isFulfilled    : { value : false },
			addBoth        : { value : addBoth ,       configurable : false , writable : false },
			addCallback    : { value : addCallback ,   configurable : false , writable : false },
			addErrback     : { value : addErrback ,    configurable : false , writable : false },
			fulfill        : { value : fulfill,        configurable : false , writable : false },
			unfulfill      : { value : unfulfill,      configurable : false , writable : false },
			fulfillWith    : { value : fulfillWith ,   configurable : false , writable : false },
			unfulfillWith  : { value : unfulfillWith , configurable : false , writable : false },
			toString       : { value : function(){ return "Object Deffered"; } , configurable : false , writable : false }
		}
		
		
	}()));
	
			function initDeferredObject(){
			
			return object.create( Deferred , { callbacksQueue : { value : [] , configurable : false , writable : false }, 
			                                   errbacksQueue  : { value : [] , configurable : false , writable : false }
											  } );
		}

			
				var A = (function(){
			
			var chainingArray = {
				
				_array : null,
				toString : function(){
					
					return this._array.toString();
				}
				
				};
			
			object.each(arrayExtra,function(value,key){
				
				chainingArray[key] = function(){
					
					var args = slice.call(arguments);
					
					args.unshift(this._array);
					
					return  (isArray(result = arrayExtra[key].apply(null,args)) ? A(result) : result);
				}
				
			});
			
			
			return function(array){
				
				return object.create(chainingArray,{
					_array : array
				})
		
		}}());
		
		
	  	 function getImage(url,successCallback,errorback){

	 var image        = document.createElement("img");

	     image.onload = function(){
		
			 if(isFunction( successCallback )){
			 
			 successCallback.call( null , image , url );
			 
			 }
			 
			 image.onload = null;
		 }
		 
		 image.onerror = function(){
			 
			 if( isFunction( errorback ) ){
			 
			  errorCallback.call(null);
			 
		 }
		 
		 }
		 
	     image.src = url;


 }
		

				
			
			global.proto = {
				
				object                : object,
				array                 : arrayExtra,
				extendNativePrototype : extendNativePrototype,
				isNull                : isNull,
				isPlainObject         : isPlainObject,
				isArray               : isArray,
				isFunction            : isFunction,
				isNumber              : isNumber,
				isRegExp              : isRegExp,
				isElement             : isElement,
				isTextNode            : isTextNode,
				deferred              : initDeferredObject,
				fun                   : fun,
				num                   : numTools,
				getImage              : getImage,
				toString              : function(){
				
				return "object Proto" }
				}
			


		
		
			
		  })();
