var gAuth = {
	serviceUrl :'',
	iWindow : {},
	iFbWindow : {},
	_callbacks : [],
	game_id :0,
	url :'',
	sended :false,
	registerUrl :'',
	token :0,
	email :'',
	fpUrl :'',
	feUrl :'',
	language :'',
	autologin : false,
	blankUrl: '',
	/**
	 * initialization
	 */
	init : function(obj) {
		var iframe, scripts, i;
		// retrieve service domain url
		scripts = document.getElementsByTagName('script');
		for (i in scripts) {
			if (scripts[i].src !== undefined && scripts[i].src.indexOf('gAuth.js') > 0) {
				gAuth.url = scripts[i].src.substring(0, scripts[i].src.indexOf(
						'/js/gAuth.js', 10));
				break;
			}
		}
		gAuth.serviceUrl = gAuth.url + '/gauth/login';
		
		//language given ? use it : retrieve it
		if (obj.language !== undefined) {
			gAuth.language = obj.language;
		}
		gAuth.i18n.init();
		
		//forgot e-mail url
		if(obj.autologin){
			gAuth.autologin = obj.autologin;
		}
		
		// test game_id
		if (obj.game_id !== undefined) {
			gAuth.game_id = obj.game_id;
		} else {
			throw new Error("game id is undefined");
		}
		
		// login box contaienr
		if (obj.container !== undefined && obj.container.appendChild !== undefined) {
			gAuth.display.init(obj.container);// show login box
        
		} else {
			throw new Error(
					"container is undefined or isn't an htmlDocumentElement");
		}
		
		//game register
		if (obj.registerUrl !== undefined) {
			gAuth.registerUrl = obj.registerUrl;
		} else {
			throw new Error("register url is undefined");
		}

		//forgot pass url
		if(obj.forgotPasswordUrl){
			gAuth.fpUrl = obj.forgotPasswordUrl;
		}else{
			gAuth.fpUrl = gAuth.url + '/account/regen-password/';
		}

		//forgot e-mail url
		/*if(obj.forgotEmailUrl){
			gAuth.feUrl = obj.forgotEmailUrl;
		}*/

		// test blank url
		if (obj.blankUrl !== undefined) {
		    gAuth.blankUrl = obj.blankUrl;
			iframe = document.createElement('iframe');
			iframe.style.display = 'none';
			document.getElementsByTagName('body')[0].appendChild(iframe);
			gAuth.iWindow = iframe.contentWindow;
			gAuth.iWindow.location = obj.blankUrl;
			if (obj.callback !== undefined
					&& typeof (obj.callback) == 'function') {
				gAuth.addCallback(obj.callback);
			}
			return gAuth;
		} else {
			throw new Error("blank page url is undefined");
		}
	},
	addCallback : function(/* Object? */context, /* Function */callback) {
		if (arguments.length > 1) {
			gAuth._callbacks.push( [ context, callback ]);
		} else {
			gAuth._callbacks.push( [ {}, context ]);
		}
	},

	/**
	 * send e-mail pass to ganga gauth service
	 */
	send : function(email, userpass) {
		gAuth.iWindow.name = gAuth.iWindow.location.protocol + '//'
				+ gAuth.iWindow.location.hostname 
				+ (gAuth.iWindow.location.port==''? '' : (':'+gAuth.iWindow.location.port))
				+ gAuth.blankUrl;
		gAuth.sended = true;
		gAuth.iWindow.location = gAuth.serviceUrl + '/email/' + email
				+ '/password/' + MD5(userpass) + '/game_id/' + gAuth.game_id;
	},
	
	/**
	 * send a request to gauth controller 
	 * user has clicked NO on the Light Box
	 */
	sendFb : function(game_id) {
		gAuth.iWindow.name = gAuth.iWindow.location.protocol + '//'
				+ gAuth.iWindow.location.hostname 
				+ (gAuth.iWindow.location.port==''? '' : (':'+gAuth.iWindow.location.port))
				+ gAuth.blankUrl;
		gAuth.sended = true;
		gAuth.iWindow.location = gAuth.url + '/gauth/fblogin/game_id/'+ gAuth.game_id + '/n/1';
	},
	
	/**
	 * destroy gangasession
	 */
	destroy : function() {
		gAuth.iWindow.name = gAuth.iWindow.location.protocol + '//'
				+ gAuth.iWindow.location.hostname 
				+ (gAuth.iWindow.location.port===''? '' : (':'+gAuth.iWindow.location.port))
				+ gAuth.blankUrl;
		gAuth.iWindow.location = gAuth.serviceUrl + '/destroy/1/game_id/'
				+ gAuth.game_id;
	},
	// first blank callback
	_init : function() {
		gAuth.iWindow.name = gAuth.iWindow.location.protocol + '//'
				+ gAuth.iWindow.location.hostname
				+ (gAuth.iWindow.location.port==''? '' : (':'+gAuth.iWindow.location.port))
				+ gAuth.blankUrl;
		gAuth.iWindow.location = gAuth.serviceUrl + '/game_id/' + gAuth.game_id;
	},
	// gauth service callback function
	_callback : function(w) {
	
		var status = 0, statuses = w.location.hash.slice(1).split(
				"&"), i, keyval, inted, s, c;
		gAuth.token = w.name;
		for (i = 0; s = statuses[i]; i++) {
			keyval = s.split("=");
			if (keyval[0] == "gauth") {
				inted = parseInt(keyval[1]);
				status = (inted == keyval[1] && !isNaN(inted)) ? inted
						: keyval[1];
			}
			if (keyval[0] === "token") {
				gAuth.token = keyval[1];
			}
		}
		if (status == 0) {	    
			switch (w.name) {
			case '6':
				gAuth.display.unAuthed();
				break;
			case '-6':
				gAuth.display.error(gAuth.i18n._('email_exists'));
				break;
			case '-1': // bad login
				gAuth.display.error(gAuth.i18n._('bad_login'));
				break;
			case '10': // in case of FB Connect
			    gAuth.display.lbox();
				break;
			case '-16': // pass empty
				gAuth.display.error(gAuth.i18n._('pass_empty'));
				break;
			case '-17': // email empty
				gAuth.display.error(gAuth.i18n._('email_empty'));
				break;
			case '-18': // bad game id
				gAuth.display.error(gAuth.i18n._('bad_game_id'));
				break;
			case '-3' :
				gAuth.display.error(gAuth.i18n._('member_banned'));
				break;
			case '-12': // internal error
			    gAuth.display.error(gAuth.i18n._('internal_error'));
			    break;
			default: // default
				gAuth.display.error(gAuth.i18n._('internal_error'));
			}
		} else // authed
		{
			if (!gAuth.sended) {
				gAuth.email = w.name.split('|')[1];
				gAuth.token = w.name.split('|')[0];
			}
			if(gAuth.sended || gAuth.autologin){
				for (i = 0; c = gAuth._callbacks[i]; i++) {
					c[1].call(c[0], gAuth.token);
				}
			} else {
				gAuth.display.authed();
			}
		}
	},
	detectBrowser : function() {
           var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
        
           if (typeof(jQuery) == "undefined") {
            return false;
           }
        
           if (jQuery.browser.safari && is_chrome == false) { 
            return false; // safari
           } else if (jQuery.browser.msie && parseInt(jQuery.browser.version) < 7) {
            return false; // to avoid IE 6
           }
           return true;
	},
	/**
	 * login box display management
	 */
	display : {
		container :null,
		load :null,
		form :null,
		connected :null,
		init : function(container) {
			var cssNode = document.createElement('link'), content_div = document
					.createElement('div'), load = document.createElement('img'), load_div = document
					.createElement('p'), span = document.createElement('span'), br = document
					.createElement('br'), picto = document.createElement('img');
			cssNode.type = 'text/css';
			cssNode.rel = 'stylesheet';
			cssNode.href = gAuth.url + '/css/gAuth.css';
			cssNode.media = 'screen';
			document.getElementsByTagName('head')[0].appendChild(cssNode);
		    container.innerHTML = '';
			picto.src = gAuth.url + '/img/gpicto.png';
			picto.title = 'ganganetwork';
			picto.id = 'gpicto';
			container.appendChild(content_div);
			content_div.id = 'gAuth';
			content_div.appendChild(picto);
			gAuth.display.container = content_div;
			load.src = gAuth.url + '/img/load.gif';
			load_div.className = 'l';
			load_div.style.display = 'none';
			load_div.appendChild(load);
			load_div.appendChild(br);
			load_div.appendChild(span);
			content_div.appendChild(load_div);
			gAuth.display.load = load_div;
			if (!gAuth.i18n.langLoaded) {
				gAuth.display.loading();
				gAuth.i18n.onLangLoaded = function() {
					gAuth.display.loading(gAuth.i18n._('l'));
				}
			} else {
				gAuth.display.loading(gAuth.i18n._('l'));
			}
		},
		loading : function() {
			text = (arguments.length > 0 && gAuth.i18n.langLoaded) ? arguments[0]
					: '';
			if (gAuth.display.form !== null) {
				gAuth.display.form.style.display = 'none';
			}
			if (gAuth.display.connected !== null) {
				gAuth.display.connected.style.display = 'none';
			}
			gAuth.display.load.style.display = 'block';
			gAuth.display.load.getElementsByTagName('span')[0].innerHTML = text;
		},
		unAuthed : function() {
			if (!gAuth.i18n.langLoaded) {
				gAuth.i18n.onLangLoaded = function() {
					gAuth.display.unAuthed();
				}
				return;
			}
			if (gAuth.display.form === null) {
				var form = document.createElement('form'),
					label_email = document.createElement('label'), 
					label_pass = document.createElement('label'), 
					input_email = document.createElement('input'), 
					input_pass = document.createElement('input'), 
					submit = document.createElement('input'), 
					a_pass = document.createElement('a'),
					//a_email = document.createElement('a'), 
					fbconnect = document.createElement('iframe'), 
					warning = document.createElement('img'), 
					a_inscription = document.createElement('a'), 
					div = document.createElement('div'), 
					error = document.createElement('span'),
					br1 = document.createElement('br'),
					br2 = document.createElement('br'),
					//br3 = document.createElement('br'),
					br4 = document.createElement('br');
				gAuth.iFbWindow = fbconnect;
				label_email.innerHTML = gAuth.i18n._('label_email');
				label_pass.innerHTML = gAuth.i18n._('label_pass');
				input_email.type = 'text';
				input_pass.type = 'password';
				input_email.name = 'email';
				input_pass.name = 'password';
				submit.type = 'submit';
				submit.value = gAuth.i18n._('submit');
				submit.className = 'b';
				submit.name = 'login_submit';
				warning.src = gAuth.url + '/img/picto_alert_petit.png';
				fbconnect.src = gAuth.url + '/fbiframe.php';
				fbconnect.name = parent.window.location.href + gAuth.blankUrl;
				fbconnect.enctype = 'application/x-www-form-urlencoded';
				fbconnect.width = '90px';
				fbconnect.height = '30px';
				fbconnect.scrolling = 'no';
				fbconnect.frameBorder = '0';
				fbconnect.allowTransparency = true;
				a_pass.appendChild(warning);
				a_pass.innerHTML += gAuth.i18n._('pass_forgot');
				a_pass.href = gAuth.fpUrl;
				a_inscription.innerHTML = gAuth.i18n._('inscription');
				a_inscription.className = 'i';
				a_inscription.href = gAuth.registerUrl;
				error.innerHTML = '&nbsp;';
				div.appendChild(label_email);
				div.appendChild(input_email);
				div.appendChild(br1);
				/**
				 * we dont user anymore the forgot-mail link
				 */
				/*if(gAuth.feUrl !== '' && gAuth.feUrl !== undefined){
					a_email.appendChild(warning);
					a_email.innerHTML += gAuth.i18n._('email_forgot');
					a_email.href = gAuth.feUrl;
					div.appendChild(a_email);
					div.appendChild(br3);
				}*/
				div.appendChild(label_pass);
				div.appendChild(input_pass);
				div.appendChild(br2);
				div.appendChild(a_pass);
				div.appendChild(br4);
				div.appendChild(error);
				div.appendChild(submit);
				form.appendChild(div);
				form.appendChild(a_inscription); 
								
				if (gAuth.detectBrowser() && window.location.host != gAuth.url)
				    div.appendChild(fbconnect); //fbconnect
				gAuth.display.container.appendChild(form);
				gAuth.display.form = form;
				form.onsubmit = function() {
					if (input_email.value === '') {
						gAuth.display.error(gAuth.i18n._('email_empty'));
					} else if (input_email.value.indexOf('@') <= 0
							|| input_email.value.indexOf('.', input_email.value
									.indexOf('@')) <= 0) {
						gAuth.display.error(gAuth.i18n._('bad_email'));
					} else if (input_pass.value === '') {
						gAuth.display.error(gAuth.i18n._('pass_empty'));
					} else {
						gAuth.display.loading();
						gAuth.send(input_email.value, input_pass.value);
					}
					return false;
				};
			}
			gAuth.display.form.getElementsByTagName('div')['0'].className = '';
			if (gAuth.display.form.email !== undefined) // pas ie6
			{
				delete gAuth.display.form.email.onclick;
				delete gAuth.display.form.password.onclick;
			} else // ie6
			{
				gAuth.display.form.action = 'javascript: gAuth.display.form.onsubmit();';
			}
			gAuth.display.load.style.display = 'none';
			if (gAuth.display.connected !== null) {
				gAuth.display.connected.style.display = 'none';
			}
			gAuth.display.form.style.display = 'block';
		},
		authed : function() {
			if (!gAuth.i18n.langLoaded) {
				gAuth.i18n.onLangLoaded = function() {
					gAuth.display.authed();
				}
				return;
			}
			
			gAuth.display.loading();
			gAuth.display.load.style.display = 'none';
			var content = document.createElement('div'), a_play = document
					.createElement('a'), a_logout = document.createElement('a'), h2 = document
					.createElement('h2'), input = document
					.createElement('input'), hr = document.createElement('img'), span = document
					.createElement('span');
			a_play.innerHTML = gAuth.i18n._('go');
			a_play.className = 'b';
			a_play.onclick = function() {
				for (i = 0; c = gAuth._callbacks[i]; i++) {
					c[1].call(c[0], gAuth.token);
				}
				gAuth.display.loading();
			}
			h2.innerHTML = gAuth.i18n._('welcome');
			input.name = 'email';
			input.value = gAuth.email;
			input.readonly = 'readonly';
			input.disabled = 'disabled';
			input.type = 'text';
			hr.src = gAuth.url + '/img/hr.png';
			span.innerHTML = gAuth.i18n._('connected_as');
			a_logout.innerHTML = gAuth.i18n._('logout');
			a_logout.className = 'i';
			a_logout.onclick = function() {
				gAuth.destroy();
				gAuth.display.loading();
			}
			content.appendChild(h2);
			content.appendChild(span);
			content.appendChild(input);
			content.appendChild(a_play);
			content.appendChild(hr);
			content.appendChild(a_logout);
			gAuth.display.container.appendChild(content);
			gAuth.display.connected = content;
		},
		error : function(e) {
			if (!gAuth.i18n.langLoaded) {
				gAuth.i18n.onLangLoaded = function() {
					gAuth.display.error(e);
				}
				return;
			}
			gAuth.display.unAuthed();
			var err = gAuth.display.form.getElementsByTagName('div')['0'];
			err.className = 'e';
			err.getElementsByTagName('span')[0].innerHTML = e;
			gAuth.display.form.email.onclick = gAuth.display.form.password.onclick = function() {
				gAuth.display.form.getElementsByTagName('div')['0'].className = '';
			}
		},
		lbox : function() {
		    jQuery.facebox('<span class="title">' + gAuth.i18n._('own_chz_account') + '</span><form id="popup_form"><input type="button" value="' + gAuth.i18n._('yes') + '" class="yes" onclick="parent.window.location = \'' + gAuth.url + '/account/indexFb?fb=1&game_id='+ gAuth.game_id +'\'"><input type="button" class="no" value="' + gAuth.i18n._('no') + '" onclick="gAuth.sendFb('+ gAuth.game_id +');"></form>');
		}
	},

	i18n : {
		onLangLoaded : function(){},
		langLoaded :false,
		_ : function(key) {
			if (gAuth.i18n[gAuth.language] !== undefined
					&& gAuth.i18n[gAuth.language][key] !== undefined) {
				return gAuth.i18n[gAuth.language][key];
			} else {
				return key;
			}
		},
		init : function() // source : le blog jaune
		{
			// Tout dans une grande exeption,pour éviter les erreurs
			try {
				if (gAuth.language === '') // aucune langue n'est forcé, on va
											// essayer de la détecter
				{
					// Détection de la langue du navigateur.
					try {
						gAuth.language = navigator.language.slice(0, 2);
					} catch (e) {
						// La truc pour ie
						gAuth.language = navigator.browserLanguage.slice(0, 2);
					}
					;
				}
				// création balise script pour récupérer les donnée de langue
				var script = document.createElement('script');
				script.src = gAuth.url + '/gauth/lang/lang/' + gAuth.language;
				script.type = 'text/javascript';
				document.getElementsByTagName('head')[0].appendChild(script);

			} catch (ee) {
				// Si il y a un problème, c'est le fichier javascript par
				// default qui est appelé.
				window.console.log("Erreur lors du chargement de l'internationalisation: " + ee);
			}
			;
		},
		fr : {
			l :'Déjà connecté ? Je vérifie ça !<br/>Attends un peu steuplé !',
			label_email :'E-mail :',
			label_pass :'Mot de Passe :',
			submit :'Connecte-toi !',
			pass_forget :'J\'ai oublié mon mot de passe !',
			inscription :'Inscription gratuite',
			welcome :'Bienvenue !',
			connected_as :'Compte connecté :',
			go :'Jouer !',
			logout :'Se déconnecter',
			bad_login :'Mauvais login',
			fb_registration :'Inscription FB',
			pass_empty :'mot de passe vide',
			email_empty :'e-mail vide',
			bad_game_id :'Ce jeu n\'est pas autorisé',
			internal_error :'erreur interne',
			bad_email :'e-mail invalide',
			own_chz_account : 'As-tu déjà un compte Chapatiz ?',
			yes: 'Oui',
			no: 'Non'
		}
	}
}

/*
 * md5.js 1.0b 27/06/96
 * 
 * Javascript implementation of the RSA Data Security, Inc. MD5 Message-Digest
 * Algorithm.
 * 
 * Copyright (c) 1996 Henri Torgemane. All Rights Reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purposes and without fee is hereby granted provided
 * that this copyright notice appears in all copies.
 * 
 * Of course, this soft is provided "as is" without express or implied warranty

 * of any kind.
 * 
 * 
 * Modified with german comments and some information about collisions. (Ralf
 * Mieke, ralf@miekenet.de, http://mieke.home.pages.de) French translation:
 * Serge FranÃ§ois, serge@selfhtml.org, http://fr.selfhtml.org
 */

function array(n) {
	for (i = 0; i < n; i++)
		this[i] = 0;
	this.length = n;
}

/*
 * Quelques fonctions fondamentales doivent Ãªtre transformÃ©es Ã  cause
 * d'erreurs Javascript. Essayez par exemple de calculer 0xffffffff >> 4 ... Les
 * fonctions utilisÃ©es maintenant sont il est vrai plus lentes que les
 * fonctions originales mais elles fonctionnent.
 */

function integer(n) {
	return n % (0xffffffff + 1);
}

function shr(a, b) {
	a = integer(a);
	b = integer(b);
	if (a - 0x80000000 >= 0) {
		a = a % 0x80000000;
		a >>= b;
		a += 0x40000000 >> (b - 1);
	} else
		a >>= b;
	return a;
}

function shl1(a) {
	a = a % 0x80000000;
	if (a & 0x40000000 == 0x40000000) {
		a -= 0x40000000;
		a *= 2;
		a += 0x80000000;
	} else
		a *= 2;
	return a;
}

function shl(a, b) {
	a = integer(a);
	b = integer(b);
	for ( var i = 0; i < b; i++)
		a = shl1(a);
	return a;
}

function and(a, b) {
	a = integer(a);
	b = integer(b);
	var t1 = (a - 0x80000000);
	var t2 = (b - 0x80000000);
	if (t1 >= 0)
		if (t2 >= 0)
			return ((t1 & t2) + 0x80000000);
		else
			return (t1 & b);
	else if (t2 >= 0)
		return (a & t2);
	else
		return (a & b);
}

function or(a, b) {
	a = integer(a);
	b = integer(b);
	var t1 = (a - 0x80000000);
	var t2 = (b - 0x80000000);
	if (t1 >= 0)
		if (t2 >= 0)
			return ((t1 | t2) + 0x80000000);
		else
			return ((t1 | b) + 0x80000000);
	else if (t2 >= 0)
		return ((a | t2) + 0x80000000);
	else
		return (a | b);
}

function xor(a, b) {
	a = integer(a);
	b = integer(b);
	var t1 = (a - 0x80000000);
	var t2 = (b - 0x80000000);
	if (t1 >= 0)
		if (t2 >= 0)
			return (t1 ^ t2);
		else
			return ((t1 ^ b) + 0x80000000);
	else if (t2 >= 0)
		return ((a ^ t2) + 0x80000000);
	else
		return (a ^ b);
}

function not(a) {
	a = integer(a);
	return (0xffffffff - a);
}

/* DÃ©but de l'algorithme */

var state = new array(4);
var count = new array(2);
count[0] = 0;
count[1] = 0;
var buffer = new array(64);
var transformBuffer = new array(16);
var digestBits = new array(16);

var S11 = 7;
var S12 = 12;
var S13 = 17;
var S14 = 22;
var S21 = 5;
var S22 = 9;
var S23 = 14;
var S24 = 20;
var S31 = 4;
var S32 = 11;
var S33 = 16;
var S34 = 23;
var S41 = 6;
var S42 = 10;
var S43 = 15;
var S44 = 21;

function F(x, y, z) {
	return or(and(x, y), and(not(x), z));
}

function G(x, y, z) {
	return or(and(x, z), and(y, not(z)));
}

function H(x, y, z) {
	return xor(xor(x, y), z);
}

function I(x, y, z) {
	return xor(y, or(x, not(z)));
}

function rotateLeft(a, n) {
	return or(shl(a, n), (shr(a, (32 - n))));
}

function FF(a, b, c, d, x, s, ac) {
	a = a + F(b, c, d) + x + ac;
	a = rotateLeft(a, s);
	a = a + b;
	return a;
}

function GG(a, b, c, d, x, s, ac) {
	a = a + G(b, c, d) + x + ac;
	a = rotateLeft(a, s);
	a = a + b;
	return a;
}

function HH(a, b, c, d, x, s, ac) {
	a = a + H(b, c, d) + x + ac;
	a = rotateLeft(a, s);
	a = a + b;
	return a;
}

function II(a, b, c, d, x, s, ac) {
	a = a + I(b, c, d) + x + ac;
	a = rotateLeft(a, s);
	a = a + b;
	return a;
}

function transform(buf, offset) {
	var a = 0, b = 0, c = 0, d = 0;
	var x = transformBuffer;

	a = state[0];
	b = state[1];
	c = state[2];
	d = state[3];

	for (i = 0; i < 16; i++) {
		x[i] = and(buf[i * 4 + offset], 0xff);
		for (j = 1; j < 4; j++) {
			x[i] += shl(and(buf[i * 4 + j + offset], 0xff), j * 8);
		}
	}

	/* tour 1 */
	a = FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
	d = FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
	c = FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
	b = FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
	a = FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
	d = FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
	c = FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
	b = FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
	a = FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
	d = FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
	c = FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
	b = FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
	a = FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
	d = FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
	c = FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
	b = FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */

	/* tour 2 */
	a = GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
	d = GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
	c = GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
	b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
	a = GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
	d = GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
	c = GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
	b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
	a = GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
	d = GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
	c = GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
	b = GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
	a = GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
	d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
	c = GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
	b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */

	/* tour 3 */
	a = HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
	d = HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
	c = HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
	b = HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
	a = HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
	d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
	c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
	b = HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
	a = HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
	d = HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
	c = HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
	b = HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
	a = HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
	d = HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
	c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
	b = HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */

	/* tour 4 */
	a = II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
	d = II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
	c = II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
	b = II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
	a = II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
	d = II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
	c = II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
	b = II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
	a = II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
	d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
	c = II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
	b = II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
	a = II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
	d = II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
	c = II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
	b = II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */

	state[0] += a;
	state[1] += b;
	state[2] += c;
	state[3] += d;

}
/*
 * Avec l'initialisation de Dobbertin: state[0] = 0x12ac2375; state[1] =
 * 0x3b341042; state[2] = 0x5f62b97c; state[3] = 0x4ba763ed; s'il y a une
 * collision:
 * 
 * begin 644 Message1 M7MH=JO6_>MG!X?!51$)W,CXV!A"=(!AR71,<X`Y-IIT9^Z&8L$2N'Y*Y:R.;
 * 39GIK9>TF$W()/MEHR%C4:G1R:Q"= ` end
 * 
 * begin 644 Message2 M7MH=JO6_>MG!X?!51$)W,CXV!A"=(!AR71,<X`Y-IIT9^Z&8L$2N'Y*Y:R.;
 * 39GIK9>TF$W()/MEHREC4:G1R:Q"= ` end
 */
function init() {
	count[0] = count[1] = 0;
	state[0] = 0x67452301;
	state[1] = 0xefcdab89;
	state[2] = 0x98badcfe;
	state[3] = 0x10325476;
	for (i = 0; i < digestBits.length; i++)
		digestBits[i] = 0;
}

function update(b) {
	var index, i;

	index = and(shr(count[0], 3), 0x3f);
	if (count[0] < 0xffffffff - 7)
		count[0] += 8;
	else {
		count[1]++;
		count[0] -= 0xffffffff + 1;
		count[0] += 8;
	}
	buffer[index] = and(b, 0xff);
	if (index >= 63) {
		transform(buffer, 0);
	}
}

function finish() {
	var bits = new array(8);
	var padding;
	var i = 0, index = 0, padLen = 0;

	for (i = 0; i < 4; i++) {
		bits[i] = and(shr(count[0], (i * 8)), 0xff);
	}
	for (i = 0; i < 4; i++) {
		bits[i + 4] = and(shr(count[1], (i * 8)), 0xff);
	}
	index = and(shr(count[0], 3), 0x3f);
	padLen = (index < 56) ? (56 - index) : (120 - index);
	padding = new array(64);
	padding[0] = 0x80;
	for (i = 0; i < padLen; i++)
		update(padding[i]);
	for (i = 0; i < 8; i++)
		update(bits[i]);

	for (i = 0; i < 4; i++) {
		for (j = 0; j < 4; j++) {
			digestBits[i * 4 + j] = and(shr(state[i], (j * 8)), 0xff);
		}
	}
}

/* Fin de l'algorithme MD5 */

function hexa(n) {
	var hexa_h = "0123456789abcdef";
	var hexa_c = "";
	var hexa_m = n;
	for (hexa_i = 0; hexa_i < 8; hexa_i++) {
		hexa_c = hexa_h.charAt(Math.abs(hexa_m) % 16) + hexa_c;
		hexa_m = Math.floor(hexa_m / 16);
	}
	return hexa_c;
}

var ascii = "01234567890123456789012345678901"
		+ " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		+ "[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";

function MD5(message) {
	var l, s, k, ka, kb, kc, kd;

	init();
	for (k = 0; k < message.length; k++) {
		l = message.charAt(k);
		update(ascii.lastIndexOf(l));
	}
	finish();
	ka = kb = kc = kd = 0;
	for (i = 0; i < 4; i++)
		ka += shl(digestBits[15 - i], (i * 8));
	for (i = 4; i < 8; i++)
		kb += shl(digestBits[15 - i], ((i - 4) * 8));
	for (i = 8; i < 12; i++)
		kc += shl(digestBits[15 - i], ((i - 8) * 8));
	for (i = 12; i < 16; i++)
		kd += shl(digestBits[15 - i], ((i - 12) * 8));
	s = hexa(kd) + hexa(kc) + hexa(kb) + hexa(ka);
	return s;
}

