Type.registerNamespace("Explorica");

Explorica.FBC = function() {
	Explorica.FBC.initializeBase(this);

	this._queryUrl = "/Ajax/Facebook.aspx"; 				//relative path to Explorica site interface
	this._loginUrl = "/FB.aspx?from=" + escape(document.location) + "&hash=";
	this._logoutUrl = "/My-Account.aspx?logout=true";
	this._syncUrl = "/my-account/link-facebook-account.aspx";
	this._api = null; 									//will become facebook api object						
	this._enrolled = null; 								//uids of travelers enrolled in this trip (tcCode)
	this._uid = null;
	this._aids = [];
	this._eids = [];
	this._toLoad = [];
	this._msgs = [];
	this._photoLinks = [];
	this._eventLinks = [];
	this._loading = [];
	this._errorCont = [];
	this._addCont = [];
	this._eventVals = [];
	this._eventCont = null;
	this._eventTmpl = null;
	this._albumCont = null;
	this._albShCont = null;
	this._albumTmpl = null;
	this._albShTmpl = null;
	this._photoTmpl = null;
	this._addEvCont = null;
	this._gallCont = null;
	this._invite = null;
	this._hasAccount = null;
	this._delLogout = null;
	this._delRefSuc = null;
	this._delRefFail = null;
	this._delGetEnr = null;
	this._delGetStat = null;
	this._delPostGetStat = null;
	this._delPostShareAlbum = null;
	this._delRemShareAlbum = null;
	this._delDrawAlbum = null;
	this._delPreEvent = null;
	this._delAftEvent = null;
	this._delListEvents = null;
	this._delFetchEvents = null;
	this._delDrawEvents = null;
	this._delDrawSharedAlbums = null;
	this._delFetchMyAlbums = null;
	this._delFetchSharedAlbums = null;
	this._onLogoutFunc = null;
}

Explorica.FBC.prototype = {
	initialize: function() {
		var initVars = { "reloadIfSessionStateChanged": true };
		Explorica.FBC.callBaseMethod(this, "initialize");
		this._delLogout = Function.createDelegate(this, this.logout);
		this._delRefSuc = Function.createDelegate(this, this._onRefreshSuccess);
		this._delRefFail = Function.createDelegate(this, this._onRefreshFail);
		this._delGetEnr = Function.createDelegate(this, this._onGetEnrolled);
		this._delGetStat = Function.createDelegate(this, this._onGetStatus);
		this._delPostGetStat = Function.createDelegate(this, this._onPostGetStatus);
		this._delPostShareAlbum = Function.createDelegate(this, this._onPostShareAlbum);
		this._delRemShareAlbum = Function.createDelegate(this, this._onRemShareAlbum);
		this._delDrawAlbum = Function.createDelegate(this, this._onDrawAlbum);
		this._delPreEvent = Function.createDelegate(this, this._onPrePostEvent);
		this._delAftEvent = Function.createDelegate(this, this._onAfterEventPost);
		this._delListEvents = Function.createDelegate(this, this.listEvents);
		this._delFetchEvents = Function.createDelegate(this, this._onFetchEvents);
		this._delDrawEvents = Function.createDelegate(this, this._drawEvents);
		this._delFetchSharedAlbums = Function.createDelegate(this, this._onFetchSharedAlbums);
		this._delFetchMyAlbums = Function.createDelegate(this, this._onFetchMyAlbums);
		this._delDrawSharedAlbums = Function.createDelegate(this, this._drawSharedAlbums);
		if (this._onLogoutFunc) initVars["ifUserNotConnected"] = this._onLogoutFunc;
		FB.init(Explorica.FB.key, Explorica.FBC.receiverFile, initVars);
		FB.ensureInit(Function.createDelegate(this, this._onEnsureInit));
	},
	dispose: function() {
		if (this._delLogout) delete this._delLogout;
		if (this._delRefSuc) delete this._delRefSuc;
		if (this._delRefFail) delete this._delRefFail;
		if (this._delGetEnr) delete this._delGetEnr;
		if (this._delGetStat) delete this._delGetStat;
		if (this._delPostGetStat) delete this._delPostGetStat;
		if (this._delPostShareAlbum) delete this._delPostShareAlbum;
		if (this._delRemShareAlbum) delete this._delRemShareAlbum;
		if (this._delDrawAlbum) delete this._delDrawAlbum;
		if (this._delPreEvent) delete this._delPreEvent;
		if (this._delAftEvent) delete this._delAftEvent;
		if (this._delListEvents) delete this._delListEvents;
		if (this._delFetchEvents) delete this._delFetchEvents;
		if (this._delDrawEvents) delete this._delDrawEvents;
		if (this._delFetchSharedAlbums) delete this._delFetchSharedAlbums;
		if (this._delFetchMyAlbums) delete this._delFetchMyAlbums;
		if (this._delDrawSharedAlbums) delete this._delDrawSharedAlbums;
	},
	_onEnsureInit: function() {
		FB_RequireFeatures(["Api"], Function.createDelegate(this, this._finishFBLoad));
	},
	_finishFBLoad: function() {
		this._api = FB.Facebook.apiClient;
		this._refresh(this._delPostGetStat);
	},
	_getFBDate: function(inDateTime, reverse) {
		if (reverse) { return new Date(parseInt(inDateTime) * 1000); }
		else { return parseInt(new Date(inDateTime).getTime() / 1000); }
	},
	_makePost: function(mode, params, cb, context) {
		if (!params) params = {};
		params.token = this.get_token();
		Explorica.makeWebRequest(this._queryUrl + "?mode=" + mode, params, cb, context, true);
	},
	_callMethod: function(method, params, callback) { this._api.callMethod(method, params, callback); },
	_delayHide: function(el) { setTimeout(function() { $(el).hide('fast'); }, 2500); },
	_displayLink: function(ar, name) {
		var l = null;
		for (var a in ar) {
			if (a == name) l = ar[a];
			else ar[a].hide();
		}
		if (l) l.show();
	},
	_logAction: function(action, content, callback, context) { this._makePost("log", { uid: this.get_uid(), tcCode: this.get_code(), action: action, content: content, url: location.href }, callback, context); },
	_rmAction: function(action, content, callback, context) { this._makePost("rmlog", { uid: this.get_uid(), tcCode: this.get_code(), action: action, content: content }, callback, context); },
	_onGetStatus: function(data, cx) {
		this._hasAccount = data;
		if (typeof (cx) != "undefined" && cx.callback) cx.callback();
	},
	_getAccountStatus: function(cb) { this._makePost("check", { uid: this.get_uid() }, this._delGetStat, { callback: cb }); },
	_onPostGetStatus: function(cb) {
		$(".fb").css({ "display": "block" });
		$(".fb.login").css({ "display": "none" });
		var h = this.get_events().getHandler("init");
		if (h) h(this, Sys.EventArgs.Empty);
	},
	_setHash: function() {
		if (!this.get_username()) location.href = this._loginUrl + "&uid=" + this._uid;
		else if (!this._hasAccount) location.href = this._syncUrl + "?from=" + escape(document.location);
		else location.href = this._loginUrl + "&uid=" + this._uid;
	},
	_refresh: function(cbSuccess, cbFailed) {
		if (this._api.get_session()) {
			this._uid = this._api.get_session().uid;
			this._getAccountStatus(cbSuccess);
		} else {
			$(".fb").css({ "display": "none" });
			$(".fb.login").css({ "display": "block" });
			if (typeof (cbFailed) != "undefined") cbFailed();
		}
	},
	_onRefreshSuccess: function() { this._setHash(); },
	_onRefreshFail: function() { },
	_renderUser: function(uid, target) {
		var html = String.format("<div class='friend'><fb:name uid='{0}' linked='false' useyou='false' ifcantsee=''></fb:name><br /><fb:profile-pic uid='{0}' size='q' linked='false'></fb:profile-pic></div>", uid);
		var container = $(html).appendTo(target).get(0);
		FB.XFBML.Host.parseDomElement(container);
	},
	_onGetEnrolled: function(ids) { // render friends on tour
		var target = $(".tourfriends.fb"), html, container;
		this._enrolled = ids;
		if (!target.length) return;
		for (var uid in ids) { this._renderUser(ids[uid], target); }
	},
	_hideEventContainers: function() { this._eventCont.hide(); this._addEvCont.hide(); this._errorCont["event"].hide(); this.get_eventLoading().hide(); },
	_showEventLoading: function() { this._hideEventContainers(); this.get_eventLoading().show(); },
	_showEventError: function(msg) {
		var cont = this._errorCont["event"];
		this._hideEventContainers();
		cont.text(msg);
		cont.show();
	},
	_setNoEvents: function() { this._showEventError(this._getMsg("noEvents")); },
	_onPrePostEvent: function(result) {
		if (result) {
			var args = {};
			args.event_info = this._collectEventData(false);
			this._callMethod("events.create", args, this._delAftEvent);
		}
	},
	_onAfterEventPost: function(eventId, ex) {
		if (ex) this._showEventError(ex.toString());
		else { this._eids.push(eventId); this._logAction("event.create", eventId, this._delListEvents); this._resetAddEvent(); }
	},
	_onFetchEvents: function(results) {
		if (results && results.length > 0) {
			this._eids = [];
			for (var r in results) {
				if (results[r]["action"] == "event.create") this._eids.push(results[r]["content"]);
			}
			if (this._eids.length > 0) this.get_api().events_get(this.get_uid(), this._eids, null, null, null, this._delDrawEvents);
			else this._drawEvents();
		} else this._drawEvents();
	},
	_drawEvents: function(results, ex) {
		var tmpl = this.get_eventTemplate(), target = this.get_eventContainer(), e, a, id, start, end;
		if (!results || !results.length) this._setNoEvents();
		else {
			target.empty();
			for (var r in results) {
				start = this._getFBDate(results[r]["start_time"], true);
				end = this._getFBDate(results[r]["end_time"], true);
				results[r]["start_short"] = start.format("dddd MMMM dd, yyyy");
				results[r]["start_time_format"] = start.format("MMM d, yyyy h:mm tt");
				results[r]["end_time_format"] = end.format("MMM d, yyyy h:mm tt");
				e = $(tmpl.evaluate(results[r]));
				e.appendTo(target);
				a = e.find("span[eid='" + results[r]["eid"] + "']");
				FB.XFBML.Host.addElement(new FB.XFBML.EventLink(a.get(0)));
				$(a.find("a").get(0)).attr("target", "_blank");
			}
			this._hideEventContainers();
			target.show();
		}
		this._displayLink(this._eventLinks, "add");
	},
	_drawSharedAlbums: function(results, ex) {
		if (typeof (results) == "undefined" || !results.length) this._showAlbumMessage(this._getMsg("noSharedAlbums"));
		else {
			var cont = this.get_albumContainer(), tmp = this.get_albumTemplate(), html, album, cover;
			cont.empty();
			for (var r in results) {
				html = tmp.evaluate(results[r]);
				album = $(html);
				album.appendTo(cont);
				cover = album.find("div[pid='" + results[r]["cover_pid"] + "']").get(0);
				FB.XFBML.Host.addElement(new FB.XFBML.Photo(cover));
			}
			this._hideAlbumContainers();
			cont.show();
		}
		this._displayLink(this._photoLinks, "share");
	},
	_onPostShareAlbum: function(data, context) {
		if (data) {
			this._aids.push(context.aid);
			$(context.link).html("remove &gt;");
		}
	},
	_onRemShareAlbum: function(data, context) {
		if (data) {
			Array.remove(this._aids, context.aid);
			$(context.link).html("share &gt;");
		}
	},
	_onDrawAlbum: function(results, ex) {
		if (typeof (results) == "undefined" || !results.length) this._showAlbumMessage(this._getMsg("noPhotos"));
		else if (ex != null) this._showAlbumMessage(ex.toString());
		else {
			var cont = this.get_galleryContainer(), tmp = this.get_photoTemplate(), html, photo;
			cont.empty();
			for (var r in results) {
				html = tmp.evaluate(results[r]);
				photo = $(html);
				photo.appendTo(cont);
			}
			FB.XFBML.Host.parseDomElement(cont.get(0));
			this._hideAlbumContainers();
			cont.show();
		}
		this._displayLink(this._photoLinks, "albums");
	},
	_onFetchMyAlbums: function(results, ex) {
		if (typeof (results) == "undefined" || !results.length) this._showAlbumMessage(this._getMsg("noMyAlbums"));
		else if (ex != null) this._showAlbumMessage(ex.toString());
		else {
			var cont = this.get_albumShareContainer(), body = $(cont.children().get(1)), tmp = this.get_albumShareTemplate(), html, album, cover, a;
			body.empty();
			for (var r in results) {
				html = tmp.evaluate(results[r]);
				album = $(html);
				album.appendTo(body);
				a = album.children(".share");
				if (a) {
					$(a).html((Array.contains(this._aids, results[r]["aid"])) ? "remove &gt;" : "share &gt;");
				}
			}
			FB.XFBML.Host.parseDomElement(body.get(0));
			this._hideAlbumContainers();
			cont.show();
		}
		this._displayLink(this._photoLinks, "albums");
	},
	_onFetchSharedAlbums: function(results) {
		if (results && results.length > 0) {
			this._aids = [];
			for (var r in results) {
				if (results[r]["action"] == "album.share") this._aids.push(results[r]["content"]);
			}
			if (this._aids.length > 0) this.get_api().photos_getAlbums(null, this._aids, this._delDrawSharedAlbums);
			else this._drawSharedAlbums();
		} else this._drawSharedAlbums();
	},
	_hideAlbumContainers: function() { this._albumCont.hide(); this._gallCont.hide(); this._albShCont.hide(); this._errorCont["album"].hide(); this.get_albumLoading().hide(); },
	_showAlbumLoading: function() { this._hideAlbumContainers(); this.get_albumLoading().show(); },
	_showAlbumMessage: function(msg) { var cont = this._errorCont["album"]; this._hideAlbumContainers(); cont.text(msg); cont.show(); },
	_getActions: function(action, callback) { this._makePost("getlogs", { tcCode: this.get_code(), action: action }, callback); },
	_resetAddEvent: function() { for (var a in this._addCont) this._addCont[a].val(""); for (var a in this._eventVals) this._eventVals[a].hide(); },
	_validateEventData: function() { return false; },
	_getDateTime: function(d, h, m, t) { if (d != "" && h != "" && m != "" && t != "") { return this._getFBDate(String.format("{0} {1}:{2} {3}", d, h, m, t), false); } else return null; },
	_getMsg: function(k) { return this._msgs[k]; },
	_collectEventData: function(validating) {
		var c = this._addCont, v = this._eventVals, x = true, now = this._getFBDate(new Date(), false);
		var title = c.addTitle.val(), startDate = this._getDateTime(c.addSDate.val(), c.addSHour.val(), c.addSMin.val(), c.addSType.val()),
			endDate = this._getDateTime(c.addEDate.val(), c.addEHour.val(), c.addEMin.val(), c.addEType.val()), priv = c.addPrivacy.val();
		if (title == "") { v.name.show(); x = false; } else v.name.hide();
		if (startDate == null) { v.start.text(this._getMsg("validDate")); v.start.show(); x = false; } else if (startDate < now) { v.start.text(this._getMsg("pastDate")); v.start.show(); x = false; } else v.start.hide();
		if (endDate == null) { v.end.text(this._getMsg("validDate")); v.end.show(); x = false; } else if (endDate < now) { v.end.text(this._getMsg("pastDate")); v.end.show(); x = false; } else v.end.hide();
		if (startDate != null && endDate != null && endDate < startDate) { v.end.text(this._getMsg("overlapDate")); v.end.show(); x = false; }
		if (priv == "") { v.privacy.show(); x = false; } else v.privacy.hide();
		if (validating) return x;
		else if (x) {
			return { category: "4", subcategory: "34", name: title, host: c.addHost.val(), location: c.addLocation.val(), street: c.addStreet.val(),
				city: c.addCity.val(), description: c.addDesc.val(), privacy_type: priv, start_time: startDate, end_time: endDate
			};
		} else return null;
	},
	login: function() { this._refresh(this._delRefSuc, this._delRefFail); },
	logout: function() { location.href = this._logoutUrl; },
	listEnrolledFriends: function() { this._makePost("members", { "tcCode": this.get_code() }, this._delGetEnr); },
	promptInviteForm: function() { this._invite.show(); },
	promptAddEvent: function() {
		this._resetAddEvent();
		this._hideEventContainers();
		this.get_addEventContainer().show();
		this._displayLink(this._eventLinks, "cancel");
	},
	cancelAddEvent: function() {
		this._hideEventContainers();
		if (this._eids.length > 0) this.get_eventContainer().show();
		else this._errorCont["event"].hide();
		this._displayLink(this._eventLinks, "add");
	},
	createEvent: function() { if (this._collectEventData(true)) FB.Connect.showPermissionDialog("create_event", this._delPreEvent); },
	listEvents: function() {
		this._showEventLoading();
		if (this._eids == null) this._getActions("event.create", this._delFetchEvents);
		else if (this._eids.length > 0) this.get_api().events_get(this.get_uid(), this._eids.join(), null, null, null, this._delDrawEvents);
		else this._drawEvents();
	},
	listMyAlbums: function() {
		this._showAlbumLoading();
		this.get_api().photos_getAlbums(this.get_uid(), null, this._delFetchMyAlbums);
	},
	listSharedAlbums: function() {
		this._showAlbumLoading();
		if (this._aids == null) this._getActions("album.share", this._delFetchSharedAlbums);
		else if (this._aids.length > 0) this.get_api().photos_getAlbums(null, this._aids, this._delDrawSharedAlbums);
		else this._drawSharedAlbums();
	},
	shareAlbum: function(aid, link) {
		if (Array.contains(this._aids, aid)) this._rmAction("album.share", aid, this._delRemShareAlbum, { aid: aid, link: link });
		else this._logAction("album.share", aid, this._delPostShareAlbum, { aid: aid, link: link });
	},
	viewAlbum: function(aid) { this._showAlbumLoading(); this.get_api().photos_get(null, aid, null, this._delDrawAlbum); },
	get_api: function() { return this._api; },
	get_token: function() { return Explorica.FB.authToken; },
	get_code: function() { return Explorica.FB.tcCode; },
	get_hash: function() { return Explorica.FB.hash; },
	get_username: function() { return Explorica.FB.username; },
	get_uid: function() { return this._uid; },
	initControls: function(albums, events, invite, msgs) {
		if (albums) {
			this._albumCont = $(albums.albumContainer);
			this._gallCont = $(albums.galleryContainer);
			this._albShCont = $(albums.addView);
			this._albumTmpl = new Template(albums.albumTemplate);
			this._albShTmpl = new Template(albums.shareTemplate);
			this._photoTmpl = new Template(albums.photoTemplate);
			this._loading["album"] = $(albums.albumLoading);
			this._errorCont["album"] = $(albums.error);
			this._photoLinks["share"] = $(albums.shareLink);
			this._photoLinks["albums"] = $(albums.albumsLink);
			this._photoLinks["gallery"] = $(albums.galleryLink);
			this._aids = albums.aids;
		}
		if (events) {
			this._eventTmpl = new Template(events.eventTemplate);
			this._eventCont = $(events.eventContainer);
			this._addEvCont = $(events.addEventContainer);
			this._loading["event"] = $(events.eventLoading);
			this._errorCont["event"] = $(events.error);
			this._eventLinks["add"] = $(events.addLink);
			this._eventLinks["cancel"] = $(events.cancelLink);
			this._eids = events.eids;
			for (var a in events.addControls) this._addCont[a] = $(events.addControls[a]);
			for (var a in events.val) this._eventVals[a] = $(events.val[a]);
		}
		if (invite) this._invite = $(invite);
		if (msgs) this._msgs = msgs;
	},
	get_albumContainer: function() { return this._albumCont; },
	get_albumShareContainer: function() { return this._albShCont; },
	get_galleryContainer: function() { return this._gallCont; },
	get_albumTemplate: function() { return this._albumTmpl; },
	get_albumShareTemplate: function() { return this._albShTmpl; },
	get_photoTemplate: function() { return this._photoTmpl; },
	get_albumLoading: function() { return this._loading["album"]; },
	get_eventContainer: function() { return this._eventCont; },
	get_addEventContainer: function() { return this._addEvCont; },
	get_eventLoading: function() { return this._loading["event"]; },
	get_eventTemplate: function() { return this._eventTmpl; },
	get_onLogoutFunction: function() { return this._onlogoutFunc; },
	set_onLogoutFunction: function(f) { this._onLogoutFunc = f; },
	add_initialized: function(h) { this.get_events().addHandler("init", h); },
	remove_initialized: function(h) { this.get_events().removeHandler("init", h); }
}

Explorica.FBC.receiverFile = "/xd_receiver.html"; 			//location of cross domain communications file
Explorica.FBC.initialize = function(initHandler, logoutHandler) {
	if (typeof (Explorica.FBC._instance) == "undefined" || Explorica.FBC._instance == null) {
		Explorica.FBC._instance = $create(Explorica.FBC, (logoutHandler) ? { onLogoutFunction:logoutHandler } : null, { initialized: initHandler });
	} else initHandler(Explorica.FBC._instance, Sys.EventArgs.Empty);
}
Explorica.FBC.registerClass("Explorica.FBC", Sys.Component);

if (typeof (Sys) !== "undefined") Sys.Application.notifyScriptLoaded();

function Template(tmpl) {
	this.tmplText = $(tmpl).html();
	this.evaluate = function(obj) {
		var matches = this.tmplText.match(/\#\{[^}]+\}/g);
		var outTxt = this.tmplText;
		for (var match = 0; match < matches.length; match++) {
			var property = matches[match].replace(/[{}#]/g, '');
			var newVal = "";
			if (obj && obj[property]) newVal = obj[property];
			outTxt = outTxt.replace(matches[match], newVal);

		}
		return outTxt;
	}
}
/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */
var hexcase=0;function hex_md5(a){return rstr2hex(rstr_md5(str2rstr_utf8(a)))}function hex_hmac_md5(a,b){return rstr2hex(rstr_hmac_md5(str2rstr_utf8(a),str2rstr_utf8(b)))}function md5_vm_test(){return hex_md5("abc").toLowerCase()=="900150983cd24fb0d6963f7d28e17f72"}function rstr_md5(a){return binl2rstr(binl_md5(rstr2binl(a),a.length*8))}function rstr_hmac_md5(c,f){var e=rstr2binl(c);if(e.length>16){e=binl_md5(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binl_md5(a.concat(rstr2binl(f)),512+f.length*8);return binl2rstr(binl_md5(d.concat(g),512+128))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d<c.length;d++){a=c.charCodeAt(d);b+=f.charAt((a>>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d<c.length){a=c.charCodeAt(d);e=d+1<c.length?c.charCodeAt(d+1):0;if(55296<=a&&a<=56319&&56320<=e&&e<=57343){a=65536+((a&1023)<<10)+(e&1023);d++}if(a<=127){b+=String.fromCharCode(a)}else{if(a<=2047){b+=String.fromCharCode(192|((a>>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binl(b){var a=Array(b.length>>2);for(var c=0;c<a.length;c++){a[c]=0}for(var c=0;c<b.length*8;c+=8){a[c>>5]|=(b.charCodeAt(c/8)&255)<<(c%32)}return a}function binl2rstr(b){var a="";for(var c=0;c<b.length*32;c+=8){a+=String.fromCharCode((b[c>>5]>>>(c%32))&255)}return a}function binl_md5(p,k){p[k>>5]|=128<<((k)%32);p[(((k+64)>>>9)<<4)+14]=k;var o=1732584193;var n=-271733879;var m=-1732584194;var l=271733878;for(var g=0;g<p.length;g+=16){var j=o;var h=n;var f=m;var e=l;o=md5_ff(o,n,m,l,p[g+0],7,-680876936);l=md5_ff(l,o,n,m,p[g+1],12,-389564586);m=md5_ff(m,l,o,n,p[g+2],17,606105819);n=md5_ff(n,m,l,o,p[g+3],22,-1044525330);o=md5_ff(o,n,m,l,p[g+4],7,-176418897);l=md5_ff(l,o,n,m,p[g+5],12,1200080426);m=md5_ff(m,l,o,n,p[g+6],17,-1473231341);n=md5_ff(n,m,l,o,p[g+7],22,-45705983);o=md5_ff(o,n,m,l,p[g+8],7,1770035416);l=md5_ff(l,o,n,m,p[g+9],12,-1958414417);m=md5_ff(m,l,o,n,p[g+10],17,-42063);n=md5_ff(n,m,l,o,p[g+11],22,-1990404162);o=md5_ff(o,n,m,l,p[g+12],7,1804603682);l=md5_ff(l,o,n,m,p[g+13],12,-40341101);m=md5_ff(m,l,o,n,p[g+14],17,-1502002290);n=md5_ff(n,m,l,o,p[g+15],22,1236535329);o=md5_gg(o,n,m,l,p[g+1],5,-165796510);l=md5_gg(l,o,n,m,p[g+6],9,-1069501632);m=md5_gg(m,l,o,n,p[g+11],14,643717713);n=md5_gg(n,m,l,o,p[g+0],20,-373897302);o=md5_gg(o,n,m,l,p[g+5],5,-701558691);l=md5_gg(l,o,n,m,p[g+10],9,38016083);m=md5_gg(m,l,o,n,p[g+15],14,-660478335);n=md5_gg(n,m,l,o,p[g+4],20,-405537848);o=md5_gg(o,n,m,l,p[g+9],5,568446438);l=md5_gg(l,o,n,m,p[g+14],9,-1019803690);m=md5_gg(m,l,o,n,p[g+3],14,-187363961);n=md5_gg(n,m,l,o,p[g+8],20,1163531501);o=md5_gg(o,n,m,l,p[g+13],5,-1444681467);l=md5_gg(l,o,n,m,p[g+2],9,-51403784);m=md5_gg(m,l,o,n,p[g+7],14,1735328473);n=md5_gg(n,m,l,o,p[g+12],20,-1926607734);o=md5_hh(o,n,m,l,p[g+5],4,-378558);l=md5_hh(l,o,n,m,p[g+8],11,-2022574463);m=md5_hh(m,l,o,n,p[g+11],16,1839030562);n=md5_hh(n,m,l,o,p[g+14],23,-35309556);o=md5_hh(o,n,m,l,p[g+1],4,-1530992060);l=md5_hh(l,o,n,m,p[g+4],11,1272893353);m=md5_hh(m,l,o,n,p[g+7],16,-155497632);n=md5_hh(n,m,l,o,p[g+10],23,-1094730640);o=md5_hh(o,n,m,l,p[g+13],4,681279174);l=md5_hh(l,o,n,m,p[g+0],11,-358537222);m=md5_hh(m,l,o,n,p[g+3],16,-722521979);n=md5_hh(n,m,l,o,p[g+6],23,76029189);o=md5_hh(o,n,m,l,p[g+9],4,-640364487);l=md5_hh(l,o,n,m,p[g+12],11,-421815835);m=md5_hh(m,l,o,n,p[g+15],16,530742520);n=md5_hh(n,m,l,o,p[g+2],23,-995338651);o=md5_ii(o,n,m,l,p[g+0],6,-198630844);l=md5_ii(l,o,n,m,p[g+7],10,1126891415);m=md5_ii(m,l,o,n,p[g+14],15,-1416354905);n=md5_ii(n,m,l,o,p[g+5],21,-57434055);o=md5_ii(o,n,m,l,p[g+12],6,1700485571);l=md5_ii(l,o,n,m,p[g+3],10,-1894986606);m=md5_ii(m,l,o,n,p[g+10],15,-1051523);n=md5_ii(n,m,l,o,p[g+1],21,-2054922799);o=md5_ii(o,n,m,l,p[g+8],6,1873313359);l=md5_ii(l,o,n,m,p[g+15],10,-30611744);m=md5_ii(m,l,o,n,p[g+6],15,-1560198380);n=md5_ii(n,m,l,o,p[g+13],21,1309151649);o=md5_ii(o,n,m,l,p[g+4],6,-145523070);l=md5_ii(l,o,n,m,p[g+11],10,-1120210379);m=md5_ii(m,l,o,n,p[g+2],15,718787259);n=md5_ii(n,m,l,o,p[g+9],21,-343485551);o=safe_add(o,j);n=safe_add(n,h);m=safe_add(m,f);l=safe_add(l,e)}return Array(o,n,m,l)}function md5_cmn(h,e,d,c,g,f){return safe_add(bit_rol(safe_add(safe_add(e,h),safe_add(c,f)),g),d)}function md5_ff(g,f,k,j,e,i,h){return md5_cmn((f&k)|((~f)&j),g,f,e,i,h)}function md5_gg(g,f,k,j,e,i,h){return md5_cmn((f&j)|(k&(~j)),g,f,e,i,h)}function md5_hh(g,f,k,j,e,i,h){return md5_cmn(f^k^j,g,f,e,i,h)}function md5_ii(g,f,k,j,e,i,h){return md5_cmn(k^(f|(~j)),g,f,e,i,h)}function safe_add(a,d){var c=(a&65535)+(d&65535);var b=(a>>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)}function bit_rol(a,b){return(a<<b)|(a>>>(32-b))};