// JavaScript Document
function openWindow(url,target,resize,w,h,top,left,scrbar) {

	var new_win = window.open(url,target,"width="+w+",height="+h+",resizable="+resize+",top=50,scrollbars="+scrbar+",menubar=no,toolbar=no,directories=no,location=no,status=no,top="+top+",left="+left);
	new_win.origen=window;
}
function openPictureWindow(target,imageName,imageWidth,imageHeight,alt,posTop,posLeft) {
	newWindow = window.open("",target,"width="+imageWidth+",height="+imageHeight+",left="+posLeft+",top="+posTop);
	newWindow.document.open();
	newWindow.document.write('<html><title>'+alt+'</title><body bgcolor="#FFFFFF" leftmargin="0" topmargin="0" marginheight="0" marginwidth="0">'); 
	newWindow.document.write('<div id="base" style="position:absolute; left:0px; top:0px; width:'+imageWidth+'; height:'+imageHeight+'; z-index:1"><img src='+imageName+' width='+imageWidth+' height='+imageHeight+' alt='+alt+'><meta HTTP-EQUIV="imagetoolbar" CONTENT="no"></div>'); 
	newWindow.document.write('</body></html>');
	newWindow.document.close();
	newWindow.focus();
}

var cal;
//Efectos iframe1

var fx_sub_iframe1 = new Fx.Styles();	//Efecto del sub_iframe que se desvanece
var fx_titulo = new Fx.Styles();
var fx_submit = new Fx.Styles();
var fx_imagen_1 = new Fx.Styles();		// Efecto que aparece una imagen moviendose.
var fx_slyde = new Fx.Styles();	
var fx_fotos = new Fx.Styles();


//Funcion que pone la imegen dada por el id_foto con el efecto fx_imagen_1
var fx_efecto_1_poner = function(id_foto,varLeft,varTop){};
//Funcion que quita el sub_iframe1 con el efecto fx_sub_iframe1
var fx_iframe1_quitar = function() {};
//Funcion que realiza el efecto fx_titulo al objeto id_titulo
var fx_color_titulo = function(id_titulo){};
//Funcion que realiza el efecto del scroll
var fx_scroll_fotos = function(){};

var fx_imagen_1_poner = function(){};

var fx_imagen_1_poner_bbc = function(){};

var fx_color_submit = function(){};



var fx_color_submenu = function(color_link, color_link_on){};
var fx_color_bbc_entry = function(color_link, color_link_on){};
var fx_color_hm_entry = function(color_link, color_link_on){};
var quitar_menu = function() {};
var poner_menu = function() {};
var quitar_menu_bbc = function() {};
var poner_menu_bbc = function() {};
var fx_menu_res;					//Objeto menu
var fx_menu_carta;					//Objeto menu
var fx_menu_vinos;					//Objeto menu
var fx_menu_salon;					//Objeto menu
var fx_menu_banq;					//Objeto menu
var fx_menu_menus;					//Objeto menu
var logo_red;						//Objeto logo
var logo_orange;					//Objeto logo
var logo_yellow;					//Objeto logo
var logo_green;						//Objeto logo
var logo_blue;						//Objeto logo
var quitar_logo = function(){};		//funcion que quita el logo actualmente puesto
var poner_logo = function(){};		//funcion que coloca el logo dado por parametro
var quitar_logo_bbc = function(){};		//funcion que quita el logo actualmente puesto
var poner_logo_bbc = function(){};		//funcion que coloca el logo dado por parametro

var uploadComplete_single = function(){};
var fileUpload_single = function(){};



window.addEvent('domready', function(){
									 
	// Menu principal
	var szNormal = 120, szSmall  = 97, szFull   = 210;
	var kwicks = $$("#kwicks .kwick");
	var fx_kwicks = new Fx.Elements(kwicks, {wait: false, duration: 300, transition: Fx.Transitions.Back.easeOut});
	kwicks.each(function(kwick, i) {
		kwick.addEvent("mouseenter", function(event) {
			var o = {};
			o[i] = {width: [kwick.getStyle("width").toInt(), szFull]}
			kwicks.each(function(other, j) {
				if(i != j) {
					var w = other.getStyle("width").toInt();
					if(w != szSmall) o[j] = {width: [w, szSmall]};
				}
			});
			fx_kwicks.start(o);
		});
		kwick.addEvent("mouseleave", function(event) {
			var o = {};
			kwicks.each(function(kwick, i) {
				o[i] = {width: [kwick.getStyle("width").toInt(), szNormal]}
			});
			fx_kwicks.start(o);
		})
	
	});
	
	
	var target_red = $('target_red');
	var target_orange = $('target_orange');
	var target_yellow = $('target_yellow');
	var target_green = $('target_green');
	var target_blue = $('target_blue');
	logo_red = new Fx.Styles(target_red, {duration: 3000, wait: false});
	logo_red.options.transition = Fx.Transitions['Cubic']['easeOut'];
	logo_orange = new Fx.Styles(target_orange, {duration: 3000, wait: false});
	logo_orange.options.transition = Fx.Transitions['Cubic']['easeOut'];
	logo_yellow = new Fx.Styles(target_yellow, {duration: 3000, wait: false});
	logo_yellow.options.transition = Fx.Transitions['Cubic']['easeOut'];
	logo_green = new Fx.Styles(target_green, {duration: 3000, wait: false});
	logo_green.options.transition = Fx.Transitions['Cubic']['easeOut'];
	logo_blue = new Fx.Styles(target_blue, {duration: 3000, wait: false});
	logo_blue.options.transition = Fx.Transitions['Cubic']['easeOut'];

	
	
	
	fx_menu_res = new Fx.Styles($('menu_res'), {duration: 3000, wait: false});
	fx_menu_res.options.transition = Fx.Transitions['Back']['easeOut'];
	fx_menu_carta = new Fx.Styles($('menu_carta'), {duration: 3000, wait: false});
	fx_menu_carta.options.transition = Fx.Transitions['Back']['easeOut'];
	fx_menu_vinos = new Fx.Styles($('menu_vinos'), {duration: 3000, wait: false});
	fx_menu_vinos.options.transition = Fx.Transitions['Back']['easeOut'];
	fx_menu_salon = new Fx.Styles($('menu_salon'), {duration: 3000, wait: false});
	fx_menu_salon.options.transition = Fx.Transitions['Back']['easeOut'];
	fx_menu_menus = new Fx.Styles($('menu_menus'), {duration: 3000, wait: false});
	fx_menu_menus.options.transition = Fx.Transitions['Back']['easeOut'];
	fx_menu_banq = new Fx.Styles($('menu_banquete'), {duration: 3000, wait: false});
	fx_menu_banq.options.transition = Fx.Transitions['Back']['easeOut'];
	
	poner_menu = function(menu){
		quitar_menu();
		menu.start({	'left': [0] });
		quitar_menu = function() {
			menu.start({	'left': [450] });
		}
	};
	poner_logo = function(logo){
		quitar_logo();
		logo.start({
			'top': [10],
			'left': [350]
		});	
		quitar_logo = function(){logo.start({
			'top': [10],
			'left': [-350]
		});}
	}
	
	poner_menu_bbc = function(menu){
		quitar_menu_bbc();
		menu.start({	'right': [0] });
		quitar_menu_bbc = function() {
			menu.start({	'right': [450] });
		}
	};
	poner_logo_bbc = function(logo){
		quitar_logo_bbc();
		logo.start({
			'top': [10],
			'left': [30]
		});	
		quitar_logo_bbc = function(){logo.start({
			'top': [10],
			'left': [820]
		});}
	}
	
	fx_color_submenu = function(color_link, color_link_on){
		var list = $$("#box_menu .link1");
		list.each(function(element) {
			var fx = new Fx.Styles(element, {duration:350, wait:false});
			element.addEvent('mouseenter', function(){
				fx.start({
					'color': color_link_on
				});
			});
			element.addEvent('mouseleave', function(){
				fx.start({
					'color': color_link
				});
			});
		});
	};
	fx_color_bbc_entry = function(color_link,color_link_on){
		var element = $('bbc_entry');
		var fx = new Fx.Styles(element, {duration:0, wait:false});
		element.addEvent('mouseenter', function(){
			fx.start({
				'font-size': [20]
			});
		});
		element.addEvent('mouseleave', function(){
			fx.start({
				'font-size': [16]
			});
		});
		
		var effect = $('bbc_entry').effect('color', {duration: 4000});
		effect.start(color_link_on).chain(function() {
			effect.start(color_link);
		});
	};
	
	fx_color_hm_entry = function(color_link,color_link_on){
		var element = $('bbc_entry');
		var fx = new Fx.Styles(element, {duration:0, wait:false});
		element.addEvent('mouseenter', function(){
			fx.start({
				'font-size': [20]
			});
		});
		element.addEvent('mouseleave', function(){
			fx.start({
				'font-size': [16]
			});
		});
		
		var effect = $('bbc_entry').effect('color', {duration: 4000});
		effect.start(color_link_on).chain(function() {
			effect.start(color_link);
		});
	};
	
		
	fx_imagen_1_poner = function(id_foto,varLeft,varTop){
		var element = $(id_foto);
		element.setStyles({'opacity': [0.0]});
		element.setStyles({'display': 'block'});
		fx_imagen_1.stop();
		fx_imagen_1.stop();
		fx_imagen_1 = new Fx.Styles(element, {duration:2000, wait:false});
		fx_imagen_1.start({
			'opacity':	[1.0],
			'left':		[varLeft],
			'top':		[varTop]
		});
	};
	fx_imagen_1_poner_bbc = function(id_foto,varRight,varTop){
		var element = $(id_foto);
		element.setStyles({'opacity': [0.0]});
		element.setStyles({'display': 'block'});
		fx_imagen_1.stop();
		fx_imagen_1.stop();
		fx_imagen_1 = new Fx.Styles(element, {duration:2000, wait:false});
		fx_imagen_1.start({
			'opacity':	[1.0],
			'right':	[varRight],
			'top':		[varTop]
		});
	};
	fx_iframe1_quitar = function(target,func_fin){
		var element = $(target);
		fx_sub_iframe1.stop();
		fx_sub_iframe1.stop();
		fx_sub_iframe1 = new Fx.Styles(element, {duration:1000, wait:false});
		fx_sub_iframe1.start({
			'opacity': [0.0]
		}).chain(func_fin);
	};
	
	fx_color_titulo = function(id_titulo,color_link){
		var list = $$("#"+id_titulo);
		list.each(function(element) {
			fx_submit.stop();
			fx_submit = new Fx.Styles(element, {duration:1000, wait:false});
			fx_submit.start({
				'color': color_link
			});
		});
	};
	
	fx_color_submit = function(id_submit){
		var list = $$("#"+id_submit);
		list.each(function(element) {
			fx_titulo.stop();
			fx_titulo = new Fx.Styles(element, {duration:1000, wait:false});
			fx_titulo.start({
				'background-color': '#CCCCCC'
			});
		});
	};
	
	
	fx_scroll_fotos = function(container,clase){
		var imags = $$("#"+container+" ."+clase);
		fx_fotos = new Fx.Elements(imags, {wait: false, duration: 1000, transition: Fx.Transitions.Elastic.easeOut});
		var down = -1;
		imags.each(function(imag, i) {
			imag.addEvent("mouseenter", function(event) {
				var o = {};
				o[i] = {height: [80]}
				imags.each(function(other, j) {
					if((i != j)&&(down != j)) {
						o[j] = {height: [65]}
					}
				});
				fx_fotos.start(o);
			});
			imag.addEvent("mouseleave", function(event) {
				var o = {};
				imags.each(function(imag, i) {
					if(down != i) {
						o[i] = {height: [65]}
					}
				});
				fx_fotos.start(o);
			})
			imag.addEvent("click", function(event) {
				var o = {};
				imags.each(function(other, j) {
					if((down == j)&&(down != i)) {
						o[j] = {height: [65]}
					}
				});
				fx_fotos.start(o);
				down = i;
			});
		});
	};
	var images_single = new Array();
	uploadComplete_single = function(url,error,id) {
		if (error==false) {
			$('foto'+id).setStyles({'display': 'block'});
			$('foto'+id).src = url;
			var file = $('imagen'+id);
			file.title = '';
			file.style.backgroundColor='';
			file.style.color='';
		} else {
			if (images_single[id]!='#') {
				$('foto'+id).setStyles({'display': 'block'});
			}
			$('foto'+id).src = images_single[id];
			var file = $('imagen'+id);
			file.title = error;
			file.style.backgroundColor='#D9C2C2';
			file.style.color='#993300';
		}
	}
	fileUpload_single = function(url,espera,id){
		form = $('formulario_imagen'+id);
		form.action = url;
		form.submit();
		$('imagen'+id).value = '';
		var img = $('foto'+id);
		images_single[id] = img.src;
		img.src = espera;
		form.action = '#';
	}
});

//Ajax
var activar_indicator = function(){
	$$("#indicator").setStyles({'display': 'block'});
};
var desactivar_indicator = function(){
	$$("#indicator").setStyles({'display': 'none'});
};

var myXhr = new Ajax(); 
var mi_ajax = function(url,target,func_fin,cancel){
	if (!cancel) {
		myXhr.cancel();
	}
	myXhr = new Ajax(url,{
		method:			'get',
		evalScripts:	true,
		update:			target,
		onRequest: 		function(){
							activar_indicator();
						},
		onSuccess: 		function(req){
							desactivar_indicator();
							func_fin();
						},
		onFailure:		function(e) {
							desactivar_indicator();
							alert('Error: '+this.transport.status+' '+url);
						}
	}).request();
};



/*
Script: Scroller_frj.js
	Contains the <Scroller>.

License:
	MIT-style license.
*/

/*
Class: Scroller
	The Scroller is a class to scroll any element with an overflow (including the window) when the mouse cursor reaches certain buondaries of that element.
	You must call its start method to start listening to mouse movements.

Note:
	The Scroller requires an XHTML doctype.

Arguments:
	element - required, the element to scroll.
	options - optional, see options below, and <Fx.Base> options.

Options:
	area - integer, the necessary boundaries to make the element scroll.
	velocity - integer, velocity ratio, the modifier for the window scrolling speed.

Events:
	onChange - optionally, when the mouse reaches some boundaries, you can choose to alter some other values, instead of the scrolling offsets.
		Automatically passes as parameters x and y values.
*/


var Scroller_frj = new Class({

	options: {
		offset: -1,
		panoramic: 'yes',
		area: { 'x': 100, 'y': 10},
		velocity: 0.1,
		onChange: function(x, y){
			this.element.scrollTo(x, y);
		},
		change:  { 'x': 10, 'y': 10}
	},

	initialize: function(element, options){
		this.setOptions(options);
		this.element = $(element);
		this.mousemover = ([window, document].contains(element)) ? $(document.body) : this.element;
		this.el = this.element.getSize();
		if (this.options.offset==-1) {
			this.options.offset =  this.el.scrollSize['x']/2;
		}
		this.fireEvent('onChange', [this.el.scroll.x + this.options.offset , this.el.scroll.y]);
		this.options.area['x'] = (this.el.size['x']/2)-10;
		this.options.area['y'] = (this.el.size['y']/2)-10;
	},

	/*
	Property: start
		The scroller starts listening to mouse movements.
	*/
	start: function(){
		this.size_image = this.el.scrollSize['x']-this.el.scrollSize['x']/5;
		this.coord = this.getCoords.bindWithEvent(this);
		this.mousemover.addListener('mousemove', this.coord);
	},
	startxy: function(co){
		this.size_image = this.el.scrollSize['x']-this.el.scrollSize['x']/5;
		this.options.change.x = co.x;
		this.options.change.y = co.y;
		if (!this.timer) this.timer = this.scrollxy.periodical(6, this);
	},

	/*
	Property: stop
		The scroller stops listening to mouse movements.
	*/
	stop: function(){
		this.mousemover.removeListener('mousemove', this.coord);
		this.timer = $clear(this.timer);
	},
	stopxy: function(){
		this.timer = $clear(this.timer);
	},

	getCoords: function(event){
		this.page = (this.element == window) ? event.client : event.page;
		if (!this.timer) this.timer = this.scroll.periodical(6, this);
	},
	
	scroll: function(){
		var pos = this.element.getPosition();

		var change = {'x': 0, 'y': 0};
		for (var z in this.page){
			if (this.page[z] < (this.options.area[z] + pos[z])) {
				change[z] = (this.page[z] - this.options.area[z] - pos[z]) * this.options.velocity;
			}else if (this.page[z] + this.options.area[z] > (this.el.size[z] + pos[z]))
				change[z] = (this.page[z] - this.el.size[z] + this.options.area[z] - pos[z]) * this.options.velocity;
			/*
			if (this.page[z] < (this.options.area[z] + pos[z]) && el.scroll[z] != 0)
				change[z] = (this.page[z] - this.options.area[z] - pos[z]) * this.options.velocity;
			else if (this.page[z] + this.options.area[z] > (el.size[z] + pos[z]) && el.scroll[z] + el.size[z] != el.scrollSize[z])
				change[z] = (this.page[z] - el.size[z] + this.options.area[z] - pos[z]) * this.options.velocity;	*/
			
		}
		this.el = this.element.getSize();
		if (this.options.panoramic=='yes') {
			if ((this.el.scroll.x >= this.size_image-1)&&(change.x>0)) {
				this.fireEvent('onChange', [this.el.scroll.x - this.size_image-change.x, this.el.scroll.y + change.y]);
			} else if ((this.el.scroll.x <= 0)&&(change.x<0)) {
				this.fireEvent('onChange', [this.el.scroll.x + this.size_image+change.x, this.el.scroll.y + change.y]);
			} else if (change.y || change.x) {
				this.fireEvent('onChange', [this.el.scroll.x + change.x, this.el.scroll.y + change.y]);
			}
		} else {
			this.fireEvent('onChange', [this.el.scroll.x + change.x, this.el.scroll.y + change.y]);
		}
	},
	
	scrollxy: function() {
		this.el = this.element.getSize();
		if (this.options.panoramic=='yes') {
			if ((this.el.scroll.x >= this.size_image-1)&&(this.options.change.x>0)) {
				this.fireEvent('onChange', [this.el.scroll.x - this.size_image-this.options.change.x, this.el.scroll.y + this.options.change.y]);
			} else if ((this.el.scroll.x <= 0)&&(this.options.change.x<0)) {
				this.fireEvent('onChange', [this.el.scroll.x + this.size_image+this.options.change.x, this.el.scroll.y + this.options.change.y]);
			} else if (this.options.change.y || this.options.change.x) {
				this.fireEvent('onChange', [this.el.scroll.x + this.options.change.x, this.el.scroll.y + this.options.change.y]);
			}
		} else {
			this.fireEvent('onChange', [this.el.scroll.x + this.options.change.x, this.el.scroll.y + this.options.change.y]);
		}
	}
	

});

Scroller_frj.implement(new Events, new Options);









/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s){
	if (s!='') {
		return binl2hex(core_md5(str2binl(s), s.length * chrsz));
	} else {
		return '';
	}
}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length
 */
function core_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);

}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Calculate the HMAC-MD5, of a key and some data
 */
function core_hmac_md5(key, data)
{
  var bkey = str2binl(key);
  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
  return core_md5(opad.concat(hash), 512 + 128);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert a string to an array of little-endian words
 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
 */
function str2binl(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  return bin;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2str(bin)
{
  var str = "";
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
  return str;
}

/*
 * Convert an array of little-endian words to a hex string.
 */
function binl2hex(binarray)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
  }

  return str;
}

/*
 * Convert an array of little-endian words to a base-64 string
 */
function binl2b64(binarray)
{
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i += 3)
  {
    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
    }
  }
  return str;
}

