﻿// JScript File
 //<![CDATA[

<!-- Set the vars that scapi.js will need -->
var ScapiURL="http://www.scopus.com/scsearchapi/";
var _EmptyString="";

var ScapiTimeout="80000";
var TempStr;
var DisId = _EmptyString;
var scp=_EmptyString;
var inwardurl=_EmptyString;
var arEid=_EmptyString;

var finals = false;
var fieldscounter=1;
var _ArticlesCount=0;
var _AuthorList=_EmptyString;
var ScpURLSrch=_EmptyString;
var scptst = _EmptyString;

var _PrtnrID="K84CvKBR";
var _SltKy=_EmptyString;
var _QueryString="http://www.scopus.com/scopus/inward/record.url?";
var _BaseURL="eid=@@eid@@&partnerID=K84CvKBR&rel=3.0.0";
//alert("2");
//]]
/////////////////////
var i=0;
var t=0;
//var myRslts=new Array();
/////////////////////
<!-- Include scapi.js -->
var debug = new scapiDebug();
var scapi = new scapiInterface();
var searchAgain = new searchObj();


function scapiInterface(){    
	this._resultsValid = false;
	this._results = null;
	this._errors = null;
	this._warnings = null;
	this._search = null;
	this._callback = null;
	this._errorCallback = null;
	
	// **** NEW ********** //
	this._divId = null;
	this.setDivId = function(pDivId){
	DisId = pDivId;
	}
	
	// ***** END NEW ***** //
	
	this.Backend = new scapiBackend();
	
	// ****** UPDATE ******* //
	this.Renderer = new scapiListRenderer();
	// ******* END UPDATE ***** //
	
	// see here for explination of "me": 
	// http://w3future.com/html/stories/callbacks.xml
	var me = this;
	
	this._developerID = null;
	this.setDeveloperID = function(developerID){
		me._developerID = developerID;
	}
	
	//set the render location (passthrough to the renderer)
	this.setRenderLocation = function(DisId){
		this.Renderer.setRenderLocation(DisId);
	}
	//set the callback to be called when a search is compleate
	this.setCallback = function(callback){
		if(callback != null){
			this._callback = callback;
		}else{
		}
	}
		
	//runSearch and it's callback
	this.runSearch = function(searchObj){	
		me._resultsValid = false;
		me._search = searchObj;
		me.Backend.submitSearch(searchObj, me._developerID, me.runSearchCallback);
	}
	this.runSearchCallback = function(responseObj){
		me._errors = null;
		me._warnings = null;
		me._results = null;
		me._resultsValid = false;
		//<![CDATA[
		if(responseObj == "timeout"){
			if(me._errorCallback!=null){
				me._errorCallback();
			}
		}else if(responseObj.ERROR != null){
			me._errors = responseObj.ERROR.Errors;
			if(me._errorCallback!=null){
				me._errorCallback();
			}
		}else if(responseObj.PartOK != null){
			me._results = responseObj.PartOK;
			me._warnings = responseObj.PartOK.Warnings;
			me._resultsValid = true;
		}else if(responseObj.OK!= null){
			me._results = responseObj.OK;
			me._resultsValid = true;
		}
		if(me._callback!=null){
			me._callback();
		}else{
		}
		//]]
	}
	
	//search and it's callback
	this.search = function(searchObj){
		me._resultsValid = false;
		me._search = searchObj;
		me.Backend.submitSearch(searchObj, me._developerID, me.searchCallback);
	}
	this.searchCallback = function(responseObj){
		me._errors = null;
		me._warnings = null;
		me._results = null;
		me._resultsValid = false;
		//<![CDATA[
		if(responseObj == "timeout"){
			if(me._errorCallback!=null){
				me._errorCallback();
			}
		}if(responseObj.ERROR != null){
			//me.Renderer.renderErrors(responseObj.ERROR.Errors);
			if(me._errorCallback!=null){
				me._errorCallback();
			}
			me._errors = responseObj.ERROR.Errors
		}else if(responseObj.PartOK != null){
			me.Renderer.renderWarnings(responseObj);
			me._warnings = responseObj.PartOK.Warnings;
			me._results = responseObj.PartOK;
			me._resultsValid = true;
		}else if(responseObj.OK!= null){
			me.Renderer.renderResults(responseObj.OK.Results);
			me._results = responseObj.OK;
			me._resultsValid = true;
		}
		if(me._callback!=null){
			me._callback();
		}else{
		}
		//]]
	}
	
	
	//Renderer passthrough functions
	this.renderField = function(position, field){
		this.Renderer.renderField(this._results, position, field);
	}
	this.getField = function(position, field){
		return this._results.Results[position][field];
	}
	this.getTotalHits = function(){
		return this._results.TotalResults;
	}
	this.getNumResults = function(){
		return this._results.ReturnedResults;
	}
	this.getPosition = function(){
		return this._results.Position;
	}
	
	//get the last search request
	this.getLastSearchRequest = function(){
		return this._search;
	}
	
	//Debug option setters
	this.setDebug = function(value){
		debug.setDebug(value);
	}
	this.getDebug = function(){
		return debug.getDebug();
	}
	
}

//The debug class
function scapiDebug(){
	this._debug = false;
	this.setDebug = function(value){
		this._debug = value;
	}
	this.getDebug = function(){
		return this._debug;
	}
	
	//if debuging is enabled writes the message to the end of the specified div tag
	this.write = function(message){
		if(this.getDebug()){
			var newElement=document.createElement("p");
			var newtext=document.createTextNode(message);
			newElement.appendChild(newtext);
			document.getElementById("scapiDebugArea").appendChild(newElement);
		}
	}
}

//This class handles parsing the response from the server and rendering it into 
//html which is then inserted into the html page.
function scapiListRenderer(){
	//the id of the div tag to replace the contents of
	this._renderLocation = DisId;
	this._scapiURL = ScapiURL;
	
	ScpURLSrch="http://www.scopus.com/scopus/inward/author.url?@@QryStr@@";
	this._scpURLSrch = ScpURLSrch;
	this._scptst=scptst
	
	

	this._resultsTableStart = "";
	this._resultsTableEnd 	= "";
	
	
	this._documentRowStart1	= "<td valign=\"top\" width=\"11\" class=\""
	this._documentRowStart2	= "\"></td><td valign=\"top\" class=\""
	this._documentRowStart3 = "\" class=\"txt\">";
	this._documentRowEnd	= "</td></tr>";
	
	this._singlefieldtitle	= " <span class=\"txtSmall\">(found in <a href=\"http://www.scopus.com\">Scopus</a>)</span>";
	this._singlefieldcited	= " in <a href=\"http://www.scopus.com\">Scopus</a>";
	
	this._white				="whitebg";
	this._grey				="greybg";
	
	this._errorStart		= "<strong class=\"txtRedBold\">";
	this._errorEnd			= "</strong>";
	
	this._title				= "title";

	this._authlist			="authlist";
	this._authlistName		="Author(s)";
	
	this._abstract			="abstract";
	this._abstractName		="Abstract";
	
	this._sourcetitle		="sourcetitle";
	this._sourcetitleName	="Source title";
	
	this._issn				="issn";
	this._issnName			="ISSN";
	
	this._vol				="vol";
	this._volName			="Volume";
	
	this._issue				="issue";
	this._issueName			="Issue";
	
	this._page				="page";
	this._pageName			="Pages";
	
	this._pubdate			="pubdate";
	this._pubdateName		="Year";
	
	this._eid				="eid";
	this._eidName			="EID";
	
	this._scp				="scp";
	this._scpName			="Scopus ID";
	
	this._doi				="doi";
	this._doiName			="DOI";
	

	this._inwardurl			="inwardurl";
	this._inwardurlStart	="<a href=\"";
	this._inwardurlEnd		="\">View on Scopus </a>";
	
	this._fieldSeperator	=": ";
	this._fieldStart		="";
	this._fieldEnd			="<br />";
	
	this._noResults			="<strong class=\"txtRedBold\">No results were found for this search</strong>";
	
	//sets a new render location overriding the previous one
	this.setRenderLocation = function(DisId){
		if(DisId != null && DisId != ""){
			this._renderLocation = DisId;
		}else{
		}
	}
	
		//render any warnings
	this.renderWarnings = function(warnings){
		//render warnings
		var output = _EmptyString;
        //<![CDATA[
		output += this.getAllRenderedResultsString(warnings.PartOK.Results);
//]]
	
		this.writeString(output);
		 
	}

	
	this.getAllRenderedWarningsString = function(warnings){
		for (i = 0; i < warnings.length; i++){
			alert(warnings[i]);
		}
		return "";
	}
	
	//render the response
	
	this.renderResults = function(response){
		var output = _EmptyString;
		//<![CDATA[
		output += this.getAllRenderedResultsString(response);	 
		this.writeString(output);
		//]]
	}
	 
    
	this.getAllRenderedResultsString = function(results){
	//<![CDATA[
		var output = _EmptyString;
		var hilight = false;
        var tmpoutput="";
		output+="<ol> \n";
		if(results.length >0)
		{
		_ArticlesCount=results.length;
			for( var i in results)
			{
			    fieldscounter=i;
			    tmpoutput=this.getRenderedResultString(results[i], hilight);
				output += tmpoutput;
				
			}
		}
		else{
			output += this._documentRowStart1+this._white+this._documentRowStart2+this._white+this._documentRowStart3;
			output += this._noResults;
			output += this._documentRowEnd;
		}
		output+="</ol> \n";
		output += this._resultsTableEnd;
		 //]]
		return output;
	}
	
	
	this.renderField = function(response, position, field)
	{
		output = this.getRenderedFieldString(field, response.Results[position][field], true);
        this.writeString(output);
	}
	
	this.getRenderedResultString = function(result, hilight){
	    //<![CDATA[
		_AuthorList="";
        var tmpoutput="";
		output = "<li>\n";
		for(var i in result)
		{
			output += this.getRenderedFieldString(i, result[i], false);
            tmpoutput="";
		}
		output +="</li>\n";

		var tmpQStr=_BaseURL.replace('@@eid@@',arEid)
		var tmpMD5;
		
		tmpMD5=mdFive(tmpQStr + _SltKy);
		tmpQStr+= "&md5="+tmpMD5;
		inwardurl=_QueryString+tmpQStr.replace(/&/g,"&amp;");
		output = output.replace('@@inwardurl@@',inwardurl);
		output = output.replace('@@AuthList@@',_AuthorList);	
    //]]
		return output ;
	}
 
 this.getRenderedFieldString = function(field, string, single){
	    
		var output = _EmptyString;
	    var authors="";
	    
        if(string == 'null')
        {string='';}
       
		if(field == this._title)
		{
				output += "<a href=\"@@inwardurl@@\">\n";
				output += string+"</a> \n @@AuthList@@";
				output +="<br />";
		}
		else if( field == this._inwardurl)
		{
			inwardurl= string.replace(/&/g,"&amp;");
		}
		else if( field == this._sourcetitle)
		{
        if (string != null && string != "" )
        {
        output += string+", ";
        }
		} 
		else if( field == this._vol)
		{
				 if (string != null && string != "" )
		        {
			        output += "vol. "+string+ ", ";
			    }
		}
		else if( field == this._issue)
		{
		     if (string != null && string != "" )
            {
	            output += "no. "+string+", ";
	        }
		}
		else if( field == this._page)
		{

		     if (string != null && string != "" )
            {
            string=string.replace("-","&#8211;");
			output += "pp. "+string+", ";
	        }

		}else if( field == this._pubdate)
		{
			output += string;
		}
		else if( field == this._eid)
		{
			arEid=string;
		} 
		else if( field == this._scp){
		    
		    scp = string;
			 
			 
		} 
        else if( field == this._authlist){
		    _AuthorList=string;
		    _AuthorList=_AuthorList.split(" |");
            for(var i in _AuthorList)
            {
                var tmp1=_AuthorList[i].substring(_AuthorList[i].indexOf(",")+1);
                var tmp2=_AuthorList[i].substring(0,_AuthorList[i].indexOf(","));
                _AuthorList[i]=tmp1.replace(".", ". ")+" "+tmp2;
            }

			_AuthorList="<br />"+_AuthorList;
		} 
		
		return output;
	}

	this.writeString = function(output){
		//<![CDATA[
		

		document.getElementById(this._renderLocation).innerHTML =  output;
		
		
		document.getElementById("loading").style.display = "none";
		document.getElementById("loading").innerHTML= "";
		
//]]
		 
	}
}

//This class handles building and submitting the search request to the server as well as
//the callback response from the server.
function scapiBackend(){
	this._busy = false;
	this._scapiCallback = null;
	
	this._reqCounter = 0;
	this._requests = {};
	
	//Request static vars (should be config vars in a perfect world)
	this._scapiURL = ScapiURL+"search.url";
	this._timeoutVal = ScapiTimeout;
	
	//request field names
	this._preventCache = "preventCache";
	this._devID = "devId";
	this._partnerID="partnerID";
	this._search = "search";
	this._sort = "sort";
	this._sortDirection = "sortDirection";
	this._fields = "fields";
	this._numResults = "numResults";
	this._SaltKey = "SaltKey";	
	this._content = "content";
	this._offset = "offset";
	this._callback = "callback";

	//useful callback strings
	this._callbackStringStart = "scapi.Backend._requests.";
	this._callbackStringEnd = ".callback";
	
	//useful url chars
	this._equals = "=";
	this._connector = "&";
	this._post = "?";
	
	//functions calling this method need to provide a callback method which is
	//in the form function(response).  This is due to the fact that this is an 
	//asyncronus library so when control is returned, processing is not done.
	//When the search is complete submitSearch will call the callback function.
	this.submitSearch = function(searchObj, developerID, callback){
		if(this._busy == true){
			return;
		}else{
		
			//set busy to true
			this._busy = true;
			this._scapiCallback = callback;
			
			var searchRequestURL = this._scapiURL+this._post;

			//add in browser cacheing prevention.  This is used to change the generated URL
			//slightly each time to prevent the browser from caching a response to identical searches.
			//That's bad because if it happens the browser won't "run" the response.
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._preventCache,this.randomString());
			//add in developerID
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._devID,developerID);
			
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._partnerID,"K84CvKBR");

			//add in the search
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._search,searchObj.getSearch());
			
			//add in the sort
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._sort,searchObj.getSort());

			//add in the sortDirection
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._sortDirection,searchObj.getSortDirection());

			//add in the fields
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._fields,searchObj.getFields());
			
			//add in the numResults
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._numResults,searchObj.getNumResults());

			//add in the content
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._content,searchObj.getContent());
			
			//add in the offset
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._offset,searchObj.getOffset());
			
			//build the callback string
			var searchID = "search"+this._reqCounter++;
			var searchObjectString = this._callbackStringStart+searchID;
			var callbackString = this._callbackStringStart+searchID+this._callbackStringEnd;
			//add in callback
			searchRequestURL = this.appendVarToURL(searchRequestURL,this._callback,callbackString);
			
			//create a new inflight object
			flight = new inflight(searchID);
			//and add it to the requests array
			this._requests[searchID] = flight;

			// set Salt key
			//this._SltKy=searchObj.getSaltKey();
			
			
			//make the async call
			this.addRequestToHeader(searchRequestURL);
			//setup a timeout in case bad things happen
			setTimeout('scapi.Backend.timeout('+searchObjectString+')', this._timeoutVal);
		}
		scptst=searchObj.getSearch();


	}
	
	//if the value is not null this appends a field and value to an URL 
	//and returns it.  Otherwise it just returns the URL
	this.appendVarToURL = function(url, field, value){
		if(value != null && value != ""){
			url += this._connector+field+this._equals+value;
			return url;
		}else{
			return url;
		}
	}
	
	//Adds an URL to the header of an HTML document in a javascript tag
	//The purpose here is to cause the browser to load the new URL asyncronusly
	this.addRequestToHeader = function(searchURL){
		var head = document.getElementsByTagName("head")[0];
 		script = document.createElement('script');
 		script.id = 'scapiSearch';
 		script.type = 'text/javascript';
 		script.src = searchURL;
 		head.appendChild(script);
	}
	
	//Creates a random string that is 20 chars long.
	this.randomString = function() {
	//<![CDATA[
		var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
		var string_length = 20;
		var randomstring = "";
		for (var i=0; i<string_length; i++) {
			var rnum = Math.floor(Math.random() * chars.length);
			randomstring += chars.substring(rnum,rnum+1);
		}
		//]]
		return randomstring;
	}
	
	//This method is called by the inflight object when the response is returned.  At
	//that time it will handle reseting the state of the backend to idle, and the state 
	//of the request to complete, and call the callback function.
	this.callback = function(search, response){
		if(search.inflight == false){
		}else{
			search.inflight = false;
			this._busy = false;
			this._scapiCallback(response);
		}
		
	}
	
	//This method is called when the timer for a search runs down.  If the search is still active
	//at that time it resets the state of the backend to idle, marks the request as complete(timedout)
	this.timeout = function(search){
		if(search.inflight == true){
			search.inflight = false;
			this._busy = false;
			this._scapiCallback("timeout");
		}else{
		}
		//timeout code
	}
}

//This class represents any request that has been submitted to the server
//and contains an id, a status, and a callback function that is called by the 
//response from the server
function inflight(id){
	this.searchID = id;
	this.inflight = true;
	this.callback = function(response){
		scapi.Backend.callback(this,response);
	}
}
 
  
//This class is effectivly a bean, and represents all of the fields that a 
//user can specify in a search
 
function searchObj(){
	this._search = null;
	this._sort = null;
	this._sortDirection = null;
	this._fields = null;
	this._numResults = null;
	this._content = null;
	this._offset = null;
	this._SaltKey=null;
	
	//search
	 
	this.setSearch = function(search){
		this._search = search;
		 
	}
	this.getSearch = function(){
		return this._search;
	}
	
	//sort
	this.setSort = function(sort){
		this._sort = sort;
	}
	this.getSort = function(){
		return this._sort;
	}
	
	//sortDirection
	this.setSortDirection = function(sortDirection){
		this._sortDirection = sortDirection;
	}
	this.getSortDirection = function(){
		return this._sortDirection;
	}
	
	//fields
	this.setFields = function(fields){
		this._fields = fields;
	}
	this.getFields = function(){
		return this._fields;
	}
	
	//numResults
	this.setNumResults = function(numResults){
		this._numResults = numResults;
	}
	this.getNumResults = function(){
		return this._numResults;
	}
	
	//SaltKey
	this.setSaltKey = function(SaltKey){
		_SltKy = SaltKey;
	}
	this.getSaltKey = function(){
		return _SltKy;
	}
	
	
	//content
	this.setContent = function(content){
		this._content = content;
	}
	this.getContent = function(){
		return this._content;
	}
	
	//offset
	this.setOffset = function(offset){
		this._offset = offset;
	}
	this.getOffset = function(){
		return this._offset;
	}
}
     

 

function mdFive(string) {
//alert(string);
	function RotateLeft(lValue, iShiftBits) {
		return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
	}

	function AddUnsigned(lX,lY) {
		var lX4,lY4,lX8,lY8,lResult;
		lX8 = (lX & 0x80000000);
		lY8 = (lY & 0x80000000);
		lX4 = (lX & 0x40000000);
		lY4 = (lY & 0x40000000);
		lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
		if (lX4 & lY4) {
			return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
		}
		if (lX4 | lY4) {
			if (lResult & 0x40000000) {
				return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
			} else {
				return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
			}
		} else {
			return (lResult ^ lX8 ^ lY8);
		}
 	}

 	function F(x,y,z) { return (x & y) | ((~x) & z); }
 	function G(x,y,z) { return (x & z) | (y & (~z)); }
 	function H(x,y,z) { return (x ^ y ^ z); }
	function I(x,y,z) { return (y ^ (x | (~z))); }

	function FF(a,b,c,d,x,s,ac) {
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function GG(a,b,c,d,x,s,ac) {
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function HH(a,b,c,d,x,s,ac) {
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function II(a,b,c,d,x,s,ac) {
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function ConvertToWordArray(string) {
		var lWordCount;
		var lMessageLength = string.length;
		var lNumberOfWords_temp1=lMessageLength + 8;
		var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
		var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
		var lWordArray=Array(lNumberOfWords-1);
		var lBytePosition = 0;
		var lByteCount = 0;
		while ( lByteCount < lMessageLength ) {
			lWordCount = (lByteCount-(lByteCount % 4))/4;
			lBytePosition = (lByteCount % 4)*8;
			lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<<lBytePosition));
			lByteCount++;
		}
		lWordCount = (lByteCount-(lByteCount % 4))/4;
		lBytePosition = (lByteCount % 4)*8;
		lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
		lWordArray[lNumberOfWords-2] = lMessageLength<<3;
		lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
		return lWordArray;
	};

	function WordToHex(lValue) {
		var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
		for (lCount = 0;lCount<=3;lCount++) {
			lByte = (lValue>>>(lCount*8)) & 255;
			WordToHexValue_temp = "0" + lByte.toString(16);
			WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
		}
		return WordToHexValue;
	};

	function Utf8Encode(string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	};

	var x=Array();
	var k,AA,BB,CC,DD,a,b,c,d;
	var S11=7, S12=12, S13=17, S14=22;
	var S21=5, S22=9 , S23=14, S24=20;
	var S31=4, S32=11, S33=16, S34=23;
	var S41=6, S42=10, S43=15, S44=21;

	string = Utf8Encode(string);

	x = ConvertToWordArray(string);

	a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;

	for (k=0;k<x.length;k+=16) {
		AA=a; BB=b; CC=c; DD=d;
		a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
		d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
		c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
		b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
		a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
		d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
		c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
		b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
		a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
		d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
		c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
		b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
		a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
		d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
		c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
		b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
		a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
		d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
		c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
		b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
		a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
		d=GG(d,a,b,c,x[k+10],S22,0x2441453);
		c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
		b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
		a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
		d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
		c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
		b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
		a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
		d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
		c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
		b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
		a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
		d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
		c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
		b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
		a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
		d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
		c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
		b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
		a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
		d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
		c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
		b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
		a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
		d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
		c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
		b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
		a=II(a,b,c,d,x[k+0], S41,0xF4292244);
		d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
		c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
		b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
		a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
		d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
		c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
		b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
		a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
		d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
		c=II(c,d,a,b,x[k+6], S43,0xA3014314);
		b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
		a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
		d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
		c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
		b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
		a=AddUnsigned(a,AA);
		b=AddUnsigned(b,BB);
		c=AddUnsigned(c,CC);
		d=AddUnsigned(d,DD);
	}

	var temp = WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);

	return temp.toLowerCase();
}

