// myhash5 hashing algorithm analog (like md5, but very simply)
$mh5=function(v,q){
	if(!q)q=true;//64bits result
	var cc=function(_c){return (_c&&_c[0])?_c.charCodeAt(0)%127:0;};
	var shl=function(n,s){n=parseInt(n);return (s<=24)?(n<<s):((n<<24)*Math.pow(2,s-24));};
	var len=v.length;v+=' '+String.fromCharCode(cc(v[0])^0x39);v+=' '+String.fromCharCode(cc(v[2])^0x52);
	var tr=[];for(var i=0,l=v.length;i<l;i+=3){var b=0;for(var j=0;j<3;j++)b|=shl(cc(v[i+j]),7*j);var m=(b&0x7e7e0)>>9,n=(b&0xbcbc8)>>7;b&=(0xffff^((b>>16)^0xff));tr[i%3]^=b^(~m);tr[(i+1)%3]^=-b^(~n);tr[(i+2)%3]^=-b^(n|m);}
	for(var i=0;i<3;i++) tr[i]=((tr[i]+65536));
	var b64="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
	var r=""; for(var i=0;i<3;i++) r+=b64[(tr[i]>>12)&0x3f]+b64[(tr[i]>>6)&0x3f]+b64[tr[i]&0x3f];
	len%=4096;r=r.substr(0,5)+(b64[(len>>6)&0x3f]+b64[len&0x3f])+r.substr(5);
	return r;
}


/**
 * Date.format patch
 *
 * @version		0.9
 * @license		MIT License
 * @author		Alex Yaroshevich <qfox [at] ya [dot] ru>
 * @copyright		Authors
 */
if( Date.parsePatterns ) {
Date.parsePatterns.unshift( {
	//"31.12.08", "31.12.2008", "5.5.08"
	re: /^(\d{1,2})[\.](\d{1,2})[\.](\d{2,4})$/,
	handler: function(bits){
		return new Date(bits[3], bits[2] - 1, bits[1]);
	}
} );
}



/**
 * Sleep
 *
 */
function $sleep(milliseconds) {
	var start = $time();
	while( ($time() - start) < milliseconds ) {}
}

/**
 * range function
 *
 */
function $range(a,b,s) {
	var r = $A([]), from = Math.min(a,b), to = Math.max(a,b), s = Math.abs(s||1);
	for(var i=from;i<=to;i+=s) r.push(i);
	return r;
}

/**
 * Date patch
 *
 */
(function(){

var pad = function(what, length, char){
	if( length < String(what).length ) return what;
	return new Array(length - String(what).length + 1).join(char||'0') + what;
};

Date.implement('__format', Date.prototype.format);
delete Date.prototype.format;

Date.implement({
	setDay: function(day){
		day = parseInt(day||0)%7;
		this.increment('day',(7-this.get('day')+day)%7);
		return this;
	},
	getFirstSunday: function(year){
		year = $pick( year, this.get('year') );
		return (new Date()).set({'year':year,'mo':0,'date':1,'day':0}); // lang safe vs Date.parse('next sunday')
	},
	getFirstMonday: function(year){
		year = $pick( year, this.get('year') );
		return (new Date()).set({'year':year,'mo':0,'date':1,'day':1}); // lang safe vs Date.parse('next monday')
	},
	
	getUnix: function(){
		return (Date.UTC(this.get('year'),this.get('mo'),this.get('date'),
			this.get('UTCHours'), this.get('UTCMinutes'), this.get('UTCSeconds'))/Date.units.second()).floor();
	},
	
	getISOYear: function(){
		var year = parseInt(this.get('year')), dayOfYear = parseInt(this.get('dayofyear')), weekDay = this.getISODay( );
		var jan1wd = (new Date()).set({'year':year,'mo':0,'date':1}).getISODay( ); //jan1WeekDay
		
		if( 4 < jan1wd && jan1wd <= 8 - dayOfYear )
			year --;
		else if( (this.isLeapYear() ? 366 : 365) < dayOfYear + 4 - weekDay )
			year ++;
                
		return year;
	},
	getISOWeek: function(){
		var year = parseInt(this.get('year')), dayOfYear = parseInt(this.get('dayofyear')), weekDay = this.getISODay( );
		var jan1wd = (new Date()).set({'year':year,'mo':0,'date':1}).getISODay( ); // jan1WeekDay
		
		var week = 52;
		if( 4 < jan1wd && jan1wd <= 8 - dayOfYear )
			week = ( jan1wd == 5 || (jan1wd == 6 && this.clone().decrement('year').isLeapYear()) ) ? 53 : 52;
		else if( (this.isLeapYear() ? 366 : 365) < dayOfYear + 4 - weekDay )
			week = 1;
		else
			week = ( (dayOfYear + (7-weekDay) + (jan1wd-1)) / 7 ).floor() + ( jan1wd > 4 ? -1 : 0 );
                
		return week;
	},
	getISODay: function(){
		return (parseInt(this.get('day'))+6)%7+1;
	},
	format: function(f){
		if (!this.isValid()) return 'invalid date';
		
		if( $type( f ) == 'string' )
		{
		var d = this;
		f = f.replace(/%([a-z])/gi,
			function($0, $1){
				switch ($1){
					case 'e': return d.get('date');
					case 'g': return pad( d.getISOYear( ), 4).substr(2);
					case 'G': return pad( d.getISOYear( ), 4);
					case 'l': return pad( d.get('hour'), 2, ' ' );
					case 'P': return String( Date.getMsg( d.get('ampm') ) ).toLowerCase( );
					case 'r': return d.format("%I:%M:%S %p");
					case 'R': return d.format("%H:%M");
					case 'u': return d.getISODay( );
					case 'U': return pad( ((1+d.get('dayofyear')-d.getFirstSunday().get('dayofyear'))/7).ceil(), 2 );
					case 'V': return pad( d.getISOWeek( ), 2 );
					case 'W': return pad( ((1+d.get('dayofyear')-d.getFirstMonday().get('dayofyear'))/7).ceil(), 2 );
					case 's': return d.getUnix();
					case 'n': return "\n";
					case 't': return "\t";
				}
				return $0;
			}
		);
		arguments[0] = f;
		}
		
		return this.__format.apply(this, arguments);
	}
});

})();


/*
---

description: String object patch for russian letters

author:
- Alex Yaroshevich

*/
delete String.prototype.hyphenate;
delete String.prototype.capitalize;
String.implement({
	hyphenate: function(){
		return this.replace(/[A-ZА-Я]/g, function(match){
			return ('-' + match.charAt(0).toLowerCase());
		});
	},

	capitalize: function(){
		return this.replace(/([^а-яА-Яa-zA-Z0-9_]|^)([a-zа-я])/g, function(match){
			return match.toUpperCase();
		});
	},

	acronyme: function(){
		return this
			.replace(/[\b\s]?([0-9])/g,function(match){
				return ' '+match;
			})
			.replace(/([^a-zа-я0-9])/ig,' ')
			.replace(/\s+/g,' ')
			.capitalize()
			.replace(/([^A-ZА-Я0-9])/g,'');
	},

	latinate: function(ignore){
		ignore = ignore || '';

		var s = ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш',  'щ',   'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я',  'ч',  'с', 'м', 'и', 'т', 'ь', 'б', 'ю',
				'Й', 'Ц', 'У', 'К', 'Е', 'Н', 'Г', 'Ш',  'Щ',   'З', 'Х', 'Ъ', 'Ф', 'Ы', 'В', 'А', 'П', 'Р', 'О', 'Л', 'Д', 'Ж', 'Э', 'Я',  'Ч',  'С', 'М', 'И', 'Т', 'Ь', 'Б', 'Ю',
				' ', '№'],
			r = ['j', 'c', 'u', 'k', 'e', 'n', 'g', 'sh', 'sch', 'z', 'h', '',  'f', 'y', 'v', 'a', 'p', 'r', 'o', 'l', 'd', 'j', 'e', 'ya', 'ch', 's', 'm', 'i', 't', '',  'b', 'yu',
				'J', 'C', 'U', 'K', 'E', 'N', 'G', 'Sh', 'Sch', 'Z', 'H', '',  'F', 'Y', 'V', 'A', 'P', 'R', 'O', 'L', 'D', 'J', 'E', 'Ya', 'Ch', 'S', 'M', 'I', 'T', '',  'B', 'Yu',
				'_', '#'];
		var n = this;
		s.each(function(l,i){ n = n.replace(new RegExp(l,'g'),r[i]); })

		return n.replace(new RegExp('[^0-9a-z\_\-'+ignore+']+','ig'),'').replace(/\_+/g,'-');
	}
});
//		$t = str_replace( $search, $replace, $t );


