	<!-- Utils -->

	function toHexDigit(number) {
		var digits = '0123456789ABCDEF';
		return digits.charAt(number >> 4) + digits.charAt(number & 15);
	}

	function toHexString(string) {
		appendLog("HS: "+string);

		var l=strlen(string);
		if(l>64)l=64;
		var out=""+toHexDigit(l);


		for (i=0; i<l; i++) {
		//out+=toHexDigit(string.substring(i,1));
		out+=toHexDigit(string.charCodeAt(i));
		}

		appendLog("HS: "+out);
		return out;
	}


	<!-- Runtime -->

//ACS ACR 38U-CCID


	var connection = -1;
	var fileDialogOpen = 0;
	var loadOperation = 0;
	var deleteOperation = 0;
	var terminals;
	var selectedTerm=0;
var uid="";

	function init() {
		var log = document.getElementById("log");
		log.value = "";
		var log = document.getElementById("log_l1");
		log.value = "";
	}

var isTiki = 0;

  function exchangeTiki(connection, apdu) {
	  if (isTiki) {
		  var currentLength = toHexDigit(apdu.length/2 + 3);
		  apdu = "FF000000" + currentLength + "D44001" + apdu;
	  }
	  var response = exchange(connection, apdu);
	  if (isTiki) {
// !!!! what if length <=15?? -> return ""
		  return response.substring(9, 9 + ("" + response).length - 15);
	  }
	  else {
		  return response;
	  }
	  return exchange(connection, apdu);
  }

	function disconnectTerminalSelected() {
		isTiki=0;
		if (fileDialogOpen) {
			return;
		}
		if (connection == -1) {
//			alert("No connection established");
			return;
		}
		disconnectTerminal(connection);
		connection = -1;
	}

	function connectTermCore() {
//		appendLog("X1");
		listTerminalsSelected();
//		appendLog("X11");
		selectedTerm=terminals.length-1;
		if(terminals[selectedTerm]=="" && selectedTerm>0) selectedTerm--;
		appendLog("Number of Terminals: " +terminals.length);
		appendLog("Terminal Used: " +terminals[selectedTerm]);

		if (terminals[selectedTerm]=="") {
			alert("No reader!");
			return;
		}


		if (fileDialogOpen) {
			return;
		}
		disconnectTerminalSelected();
		{
		try {
//		appendLog("X3");
		connection = connectTerminal(terminals[selectedTerm]);
//		appendLog("X4");
		var atr = getATR(connection);

		var checkTiki = "FF0040000400000000";
		var response = ("" + exchange(connection, checkTiki)).split(" ").join("");
		var status = response.substring(0, 2);
		if (status == "90") {
			isTiki = 1;

			/* Antenna off/on */
			var setTimeout = "FF00000004D4320100";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}

			var setTimeout = "FF00000004D4320101";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}

			/* Check retry count to one */
			var setTimeout = "FF00000006D43205000000";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}


			/* Poll for 14443-A */
			var poll = "FF00000004D44A0100";
			var response = ("" + exchange(connection, poll)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiPoll";
				throw lastException;
			}
			var cardFound = response.substring(4, 6);
			if (cardFound == "00") {
				alert("No Waver found!");
				return;
			}
		}
		else {
			isTiki = 0;
		}		

		}
		catch(e) {
			alert("No Waver Present!");
			return;
		}
		appendLog("Got atr " + atr);		
		}
	}

	function connectMifareCore() {
//		appendLog("X1");
		listTerminalsSelected();
//		appendLog("X11");
		selectedTerm=terminals.length-1;
		if(terminals[selectedTerm]=="" && selectedTerm>0) selectedTerm--;
		appendLog("Number of Terminals: " +terminals.length);
		appendLog("Terminal Used: " +terminals[selectedTerm]);

		if (terminals[selectedTerm]=="") {
			alert("No reader!");
			return;
		}


		if (fileDialogOpen) {
			return;
		}
		disconnectTerminalSelected();
		{
		try {
//		appendLog("X3");
		connection = connectTerminal(terminals[selectedTerm]);
//		appendLog("X4");
		var atr = getATR(connection);

		var checkTiki = "FF0040000400000000";
		var response = ("" + exchange(connection, checkTiki)).split(" ").join("");
		var status = response.substring(0, 2);
		if (status == "90") {
			isTiki = 1;

			/* Disable ISO14443-4 */
			var setTimeout = "FF00000003D41224";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}

			/* Antenna off/on */
			var setTimeout = "FF00000004D4320100";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}

			var setTimeout = "FF00000004D4320101";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}

			/* Check retry count to one */
			var setTimeout = "FF00000006D43205000000";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}


			/* Poll for 14443-A */
			var poll = "FF00000004D44A0100";
			var response = ("" + exchange(connection, poll)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiPoll";
				throw lastException;
			}
			var cardFound = response.substring(4, 6);
			if (cardFound == "00") {
				alert("No Waver found!");
				return;
			}
// UID
			
			uid = response.substring(16, 16+8);
		appendLog("UID " + uid);		
		}
		else {
			alert("Not Supported Reader!!");
		}		

		}
		catch(e) {
			alert("No Waver Present!");
			return;
		}
		}
	}


	function connectTerminalSelected() {
		connectTermCore();
		gowaver();
		disconnectTerminalSelected();
	}

	function connectMTerminalSelected() {
		connectMifareCore();
		gowaver();
		disconnectTerminalSelected();
	}

	function xx_connectTerminalSelected() {
//		appendLog("X1");
		listTerminalsSelected();
//		appendLog("X11");
		selectedTerm=terminals.length-1;
		if(terminals[selectedTerm]=="" && selectedTerm>0) selectedTerm--;
		appendLog("Number of Terminals: " +terminals.length);
		appendLog("Terminal Used: " +terminals[selectedTerm]);

		if (terminals[selectedTerm]=="") {
			alert("No reader!");
			return;
		}


		if (fileDialogOpen) {
			return;
		}
		disconnectTerminalSelected();
//		appendLog("X2");

		if (connection != -1) {
			gowaver();
	//		alert("Already connected to a terminal");
			return;
		}
		else
		{
		try {
//		appendLog("X3");
		connection = connectTerminal(terminals[selectedTerm]);
//		appendLog("X4");
		var atr = getATR(connection);

		var checkTiki = "FF0040000400000000";
		var response = ("" + exchange(connection, checkTiki)).split(" ").join("");
		var status = response.substring(0, 2);
		if (status == "90") {
			isTiki = 1;

			/* Antenna off/on */
			var setTimeout = "FF00000004D4320100";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}

			var setTimeout = "FF00000004D4320101";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}

			/* Check retry count to one */
			var setTimeout = "FF00000006D43205000000";
			var response = ("" + exchange(connection, setTimeout)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiTimeout";
				throw lastException;
			}


			/* Poll for 14443-A */
			var poll = "FF00000004D44A0100";
			var response = ("" + exchange(connection, poll)).split(" ").join("");
			var status = response.substring(response.length - 4);
			if (status != "9000") {
				lastException = "tikiPoll";
				throw lastException;
			}
			var cardFound = response.substring(4, 6);
			if (cardFound == "00") {
				alert("No Waver found!");
				return;
			}
		}
		else {
			isTiki = 0;
		}		

		}
		catch(e) {
			alert("No Waver Present!");
			return;
		}
		appendLog("Got atr " + atr);		
		gowaver();
		disconnectTerminalSelected();
		}
	}


	function apduSW(string) {
			return string.substr(strlen(string)-5,5);
	}

	function apduToStr(string) {
	var ret="";
        //var l=(strlen(string)-2)/3+1;
        var l=0;
	var i;
	var c;
	var d;
	i=0;
	appendLog("ApduToStr: " + string);		
	
	l=strlen(string)-6;
	appendLog("ApduToStrLen: " + l);		
	l=(l-2)/3+1;

	while(i<l && c!=0)
	{
	c=parseInt("0x"+string.substr(i*3,2));

// hack for @ (in GSM=0x00 i.e. end of string. if not last->@)

	if(i<l-1)
	d=parseInt("0x"+string.substr((i+1)*3,2));
	else
	d=0;

	if(c==0 && d!=0)c=64;
	if(c!=0)
	{
	ret=ret+String.fromCharCode(c).toString(10);
	}
	i++;
	}

	return ret;
	}

	function sendAPDU() {
		if (fileDialogOpen) {
			return;
		}
		if (connection == -1) {
			alert("Not connected to a terminal");
			return;
		}
		var apdu = document.getElementById("apdu");
		try {
			var response = exchangeTiki(connection, apdu.value);
		}
		catch(e) {
			appendLog("EXCEPTION " + lastException);
			throw e;
		}
		appendLog("Sent " + apdu.value);
		appendLog("Received " + response);
	}

	function gpOpen() {
		if (fileDialogOpen) {
			return;
		}
		if (connection == -1) {
			alert("Not connected to a terminal");
			return;
		}
		try {
			openSecureSession(connection);
		}
		catch(e) {
			appendLog("EXCEPTION " + lastException);
			throw e;
		}
	}


	function loadCap() {
		if (fileDialogOpen) {
			return;
		}
		if (connection == -1) {
			alert("Not connected to a terminal");
			return;
		}
		try {
			var result;
			loadOperation = 1;
			fileDialogOpen = 1;
			lastException = "";
			chooseFile();
		}
		catch(e) {
			fileDialogOpen = 0;
			loadOperation = 0;
			appendLog("EXCEPTION " + lastException);
			throw e;
		}
	}

	function continueLoad(result) {
		try {
			var packageAID = ("" + result[0]).split(" ").join("");
			var appletAID = ("" + result[1]).split(" ").join("");
				
			var instanceAID = appletAID;
			var installParameters = "";

			appendLog("chooseFile - success. Package AID " + packageAID + " applet AID " + appletAID + " load blocks " + result[2]);
			// INSTALL FOR LOAD
			// No Security Domain AID, File Data Block hash, Load parameters, Load token
			var apdu = "80E60200" + (toHexDigit(packageAID.length/2 + 5)) + toHexDigit(packageAID.length/2) + packageAID + "00000000";
			var response = exchangeTiki(connection, apdu);
			if (response != "00 90 00") {
				alert("Load failed");
				return;
			}
			// LOAD BLOCKS
			for (i=0; i<result[2]; i++) {
				apdu = "80E8";
				if (i == result[2] - 1) {
					apdu += "80";
				}
				else {
					apdu += "00";
				}
				apdu += toHexDigit(i);
				var loadBlock = ("" + getLoadBlock(i)).split(" ").join("");
				apdu += toHexDigit(loadBlock.length / 2) + loadBlock;
				response = exchangeTiki(connection, apdu);
				if (response != "00 90 00") {
					alert("Load failed");
					return;
				}
			}
			// INSTALL FOR INSTALL
			apdu = "80E60C00";
			var data = toHexDigit(packageAID.length/2) + packageAID + toHexDigit(appletAID.length/2) + appletAID + toHexDigit(instanceAID.length/2) + instanceAID;
			// Append default privileges (01 00) and no Install Token
			data += "0100" + toHexDigit(2 + installParameters.length/2) + "C9" + toHexDigit(installParameters.length/2) + installParameters + "00";
			apdu = apdu + toHexDigit(data.length/2) + data;
			response = exchangeTiki(connection, apdu);
			if (response != "90 00") {
				alert("Load failed");
				return;
			}
			alert("Load successful");
		}
		catch(e) {
			appendLog("EXCEPTION " + lastException);
			throw e;
		}
	}
			
	
	function deleteCap() {
		if (fileDialogOpen) {
			return;
		}
		if (connection == -1) {
			alert("Not connected to a terminal");
			return;
		}
		try {
			var result;
			deleteOperation = 1;
			fileDialogOpen = 1;
			lastException = "";
			result = chooseFile();
		}
		catch(e) {
			fileDialogOpen = 0;
			deleteOperation = 0;
			appendLog("EXCEPTION " + lastException);
			throw e;
		}
	}

	function continueDelete(result) {
		var packageAID = ("" + result[0]).split(" ").join("");
		var appletAID = ("" + result[1]).split(" ").join("");
		var apdu = "80E40080" + toHexDigit(packageAID.length/2 + 2) + "4F" + toHexDigit(packageAID.length/2) + packageAID;
		var response = exchangeTiki(connection, apdu);
		if (response != "00 90 00") {
			alert("Delete failed");
			return;
		}
		alert("Delete successful");
	}
	

	function about() {
		if (fileDialogOpen) {
			return;
		}
		try {
			var result;
			result = getAppletInfo();
			alert(result);
		}
		catch(e) {
			appendLog("EXCEPTION " + lastException);
			throw e;
		}
	}

	function clearAPDU() {
		if (fileDialogOpen) {
			return;
		}
		var apdu = document.getElementById("apdu");
		apdu.value = "";
	}

	function clearLogs() {
		if (fileDialogOpen) {
			return;
		}
		var log = document.getElementById("log");
		log.value = "";
	}

	function listTerminalsSelected() {
		if (fileDialogOpen) {
			return;
		}
		try {
/*
//			var dropdown = document.getElementById("tst").getElementById("readers");
			var dropdown = document.getElementById("readers");
			dropdown.options.length = 0;
//		appendLog("L1");
			terminals = listTerminals();
			terminals_count=0;
//		appendLog("L2");
			for (var i=0; i<terminals.length; i++) {
				var option = document.createElement("option");
				option.text = terminals[i];
				option.value = terminals[i];
				dropdown.options.add(option);
				terminals_count++;
		appendLog("L3");
			}
*/

//		appendLog("L1");
			terminals = listTerminals();
		}
		catch (e) {
		}
//		appendLog("L4");
	}

	function onCardProxyAppletLog(msg) {
		appendLog("MSG : " + msg);
	}

	function onFileDialogNotification(resultParam) {
		var result;
		if (resultParam) {
			result = ("" + resultParam).split("|");
		}
		fileDialogOpen = 0;
		if (!result) {
			loadOperation = 0;
			deleteOperation = 0;
			if (lastException.length != 0) {
				alert("Invalid file");
				appendLog("EXCEPTION " + lastException);
			}
			return;			
		}
		if (loadOperation) {
			loadOperation = 0;
			continueLoad(result);
		}
		if (deleteOperation) {
			deleteOperation = 0;
			continueDelete(result);
		}
	}

	function appendLog(msg) {
		var log = document.getElementById("log");
		log.value += msg + "\n";
	}

	function appendLogL1(msg) {
		var log = document.getElementById("log_l1");
		log.value += msg + "\n";
	}

	function appendLogL1N(msg) {
		var log = document.getElementById("log_l1");
		log.value += msg;
	}



	function listTerms() {

		if (fileDialogOpen) {
			return;
		}
		try {
			var dropdown = document.getElementById("readers");
			dropdown.options.length = 0;
			terminals = listTerminals();
			for (var i=0; i<terminals.length; i++) {
				var option = document.createElement("option");
				option.text = terminals[i];
				option.value = terminals[i];
				dropdown.options.add(option);
			}
		}
		catch (e) {
		}

	}

var count=0;
function Progress() {
   count++;
   document.getElementById('btn1').value=count+'%';
   document.getElementById('pic1').style.width=(2*count)+'px';
/*
   if (count==100) {
      document.getElementById('btn1').style.visibility='hidden';
      document.getElementById('progressbar').style.visibility='hidden';}
*/
   if (count<100) {setTimeout('Progress()',100);}
   }


function seek_tlv(s, tag)
{
//appendLogL1("TLV "+s+" "+tag);
if(s=="")return 0;
var len=parseInt("0x"+s.substr(0,2));
var j=2;
var r=0;
var t="";
while(j<len)
{
t=s.substr(3*j,2);
//appendLogL1("T: "+j*3+" "+len+" "+t);
if(tag==t)return (j+2)*3;
r=parseInt("0x"+s.substr(3*(j+1),2));
j=j+r+2;
}
return 0;
}
