local skel_1 = [[
<html>
<head>

	<script>
		var dictionary =  {}
		function add(commaSeparated)
		{
			var fields = commaSeparated.split(",");
			var manufacturerCode = fields[0];
			var modelCode 	= fields[1];
			var modelSubCode= fields[2];
			var modelName 	= fields[3]; 
			var ATQA 		= fields[4];
			var SAK 		= fields[5];

			//In the data below, wrong endian is used. Mifare is 
			// written as "0004" instead of "0400", so we need to 
			// flip it
			ATQA = ATQA.substr(2,4)+ATQA.substr(0,2)

			var info = {
				modelCode : modelCode, 
				modelSubCode : modelSubCode,
				modelName : modelName,
				ATQA 	: ATQA, 
				SAK 	: SAK
			}
			console.log("Adding "+modelName+" , "+SAK)

			dictionary[ATQA] = dictionary[ATQA] || [];
			dictionary[ATQA].push(info)
		}
		function lookup(atqa, sak)
		{
			if (!dictionary[atqa]) return "UNKNOWN";

			var possibleMatches = [];
			for(var i = 0 ; i < dictionary[atqa].length ; i++)
			{

				var info = dictionary[atqa][i];
				console.log("Comparing "+sak+ " with "+ info.SAK);
				if(sak && info.SAK == sak)//exact match
				{
					return info.modelName;
//					possibleMatches.push(info.modelName);
				}else //SAK unknown
				{
					possibleMatches.push(info.modelName);
				}
			}
			if(possibleMatches.length > 0)
				return possibleMatches.join(" or ");
			return "UNKNOWN"
		}

		add("04,,,Mifare TNP3xxx Activision 1K,0f01,01");
		add("04,,,Mifare Mini,0004,09");
		add("04,,,Mifare Classic 1k/Mifare Plus(4 byte UID) 2K SL1,0004,08");
		add("04,,,Mifare Plus (4 byte UID) 2K SL2,0004,10");
		add("04,,,Mifare Plus (4 byte UID) 4K SL2,0004,11");
		add("04,,,Mifare Plus (4 byte UID) 4K SL1,0004,18");
		add("04,,,Mifare Plus (4 byte UID) 2K/4K SL3,0004,20");
		add("04,,,Mifare Classic 4K,0002,18");
		add("xx,,,NDEF Tags,0044,00  ");
		add("04,,,Mifare Ultralight/UltralightC,0044,04");
		add("04,,,Mifare Plus (7 byte UID) 2K SL1,0042,08");
		add("04,,,Mifare Plus (7 byte UID) 2K SL1,0044,08");
		add("04,,,Mifare Plus (7 byte UID) 4K SL1,0042,18");
		add("04,,,Mifare Plus (7 byte UID) 4K SL1,0044,18");
		add("04,,,Mifare Plus (7 byte UID),0042,10");
		add("04,,,Mifare Plus (7 byte UID),0044,10");
		add("04,,,Mifare Plus (7 byte UID),0042,11");
		add("04,,,Mifare Plus (7 byte UID),0044,11");
		add("04,,,Mifare Plus (7 byte UID),0042,20");
		add("04,,,Mifare Plus (7 byte UID),0044,20");
		add("04,,,Mifare DesFire / DesFire EV1,0344,20067577810280");
		add("04,,,JCOP31,0304,283877B14A434F503331");
		add("04,,,JCOP31 v2.4.1,0048,207877B1024A434F5076323431");
		add("04,,,JCOP41 v2.2,0048,203833B14A434F503431563232");
		add("04,,,JCOP41 v2.3.1,0004,283833B14A434F50343156323331");
		add("05,,,Mifare Classic 1K,0004,88");
		add("40,,,MPCOS,0002,98");
		add("25,,,Topaz/Topaz512/Jewel,0C00,");
		add("1D,,,FM1208SH01,0004,53");
		add("1D,,,FM1208,0008,20");
		add("Nokia,,,Mifare Classic 4K emulated by Nokia 6212,0002,38");
		add("Nokia,,,Mifare Classic 4K emulated by Nokia 6131,0008,38");
		add("04,,,Smart MX with Mifare 4K emulation,0002");
		add("04,,,Smart MX with Mifare 4K emulation,0102");
		add("04,,,Smart MX with Mifare 4K emulation,0202");
		add("04,,,Smart MX with Mifare 4K emulation,0302");
		add("04,,,Smart MX with Mifare 4K emulation,0402");
		add("04,,,Smart MX with Mifare 4K emulation,0502");
		add("04,,,Smart MX with Mifare 4K emulation,0602");
		add("04,,,Smart MX with Mifare 4K emulation,0702");
		add("04,,,Smart MX with Mifare 4K emulation,0802");
		add("04,,,Smart MX with Mifare 4K emulation,0902");
		add("04,,,Smart MX with Mifare 4K emulation,0A02");
		add("04,,,Smart MX with Mifare 4K emulation,0B02");
		add("04,,,Smart MX with Mifare 4K emulation,0C02");
		add("04,,,Smart MX with Mifare 4K emulation,0D02");
		add("04,,,Smart MX with Mifare 4K emulation,0E02");
		add("04,,,Smart MX with Mifare 4K emulation,0F02");
		add("04,,,Smart MX with Mifare 1K emulation,0004");
		add("04,,,Smart MX with Mifare 1K emulation,0104");
		add("04,,,Smart MX with Mifare 1K emulation,0204");
		add("04,,,Smart MX with Mifare 1K emulation,0304");
		add("04,,,Smart MX with Mifare 1K emulation,0404");
		add("04,,,Smart MX with Mifare 1K emulation,0504");
		add("04,,,Smart MX with Mifare 1K emulation,0604");
		add("04,,,Smart MX with Mifare 1K emulation,0704");
		add("04,,,Smart MX with Mifare 1K emulation,0804");
		add("04,,,Smart MX with Mifare 1K emulation,0904");
		add("04,,,Smart MX with Mifare 1K emulation,0A04");
		add("04,,,Smart MX with Mifare 1K emulation,0B04");
		add("04,,,Smart MX with Mifare 1K emulation,0C04");
		add("04,,,Smart MX with Mifare 1K emulation,0D04");
		add("04,,,Smart MX with Mifare 1K emulation,0E04");
		add("04,,,Smart MX with Mifare 1K emulation,0F04");
		add("04,,,Smart MX with 7 byte UID,0048");
		add("04,,,Smart MX with 7 byte UID,0148");
		add("04,,,Smart MX with 7 byte UID,0248");
		add("04,,,Smart MX with 7 byte UID,0348");
		add("04,,,Smart MX with 7 byte UID,0448");
		add("04,,,Smart MX with 7 byte UID,0548");
		add("04,,,Smart MX with 7 byte UID,0648");
		add("04,,,Smart MX with 7 byte UID,0748");
		add("04,,,Smart MX with 7 byte UID,0848");
		add("04,,,Smart MX with 7 byte UID,0948");
		add("04,,,Smart MX with 7 byte UID,0A48");
		add("04,,,Smart MX with 7 byte UID,0B48");
		add("04,,,Smart MX with 7 byte UID,0C48");
		add("04,,,Smart MX with 7 byte UID,0D48");
		add("04,,,Smart MX with 7 byte UID,0E48");
		add("04,,,Smart MX with 7 byte UID,0F48");	
	</script>

	<style>
		* {
			background-color: #2F3440;
			background-color:#232323;
			color : #F5E5C0;
			xtext-transform: uppercase;
			font-size: 1.05em;
			font-family: monospace,Arial;
		}
		table{
			float:left;
			border: 1px solid white;
		}
		td {
			empty-cells: show;
		}
		td.blockzero, .turqoise{
			color: rgb(140, 245, 193);
		}
		td.key_a, .yellow{
			color : #F8CA4D;
		}
		td.key_b, .blue{
			color : #3F5666;
		}
		td.accessconditions, .red{
			color : #EA6045;
		}
	
		td.sectorhdr{
			border-top: 1px solid white;
		}
	</style>
	<script>
	/** Jquery for the poor **/
	function dc(x){return document.createElement(x)}

	function tr(table){
		var row = dc('tr');
		table.appendChild(row);
		return row;
	}
	function td(row, text){
		var tdata = dc('td');
		row.appendChild(tdata);
		tdata.appendChild(document.createTextNode(text))
		return tdata;
	}

	/**
	* The identifiers that determine how to highlight data and present information
	**/
	var identifiers = [
		function(data)
		{
			// Should be 32 characters long ( 16 bytes per block)
			if(data[0].length != 32) { return false; }
			// ... add more checks if necessary ... 

			var info = {Type : "Mifare"}
			info['Size'] = (data[0].length / 2 * data.length) + " Bytes";
			info['UID'] = data[0].substring(0,8);
			info['SAK'] = data[0].substring(10,12);
			info['ATQA'] = data[0].substring(12,16);

			info['Name'] = lookup(info.ATQA, info.SAK);
			return {info: info, highlighter : mifareHighlighter }
		},
		function(data)
		{
			// Should be 8 characters long ( 4 bytes per block)
			if(data[0].length != 8) { return false; }
			// ... add more checks if necessary ... 
			var info = {Type : "NDEF"}
			info['Size'] = (data[0].length / 2 * data.length) + " Bytes";

			return {info: info, highlighter : ndefHighligheter }
		}, 

		function(data)
		{//This is the catch-all
			return {info: {type : "Unknown"}, highlighter : noHighlighter}
		}
	]
	

	/**
	* Helper function to convert bin-data into printable chars
	**/

	function to_ascii(hexval)
	{
		var intval = parseInt(hexval,16);
		if(intval > 31 && intval < 127)
		{
			return String.fromCharCode(intval);
		}
		return ".";
	}


	function loadIntoTable(data, info, ascii)
	{
		var t = dc("table")
		for(var i = 0 ; i < data.length ; i++)
		{
			line = data[i];
			var row = tr(t);
			var bytes = line.match(/(.{1,2})/g);
			for(var b = 0 ; b < bytes.length ; b++)
			{
					var elem = td(row, ascii ? to_ascii(bytes[b]) : bytes[b]);
					info.highlighter.addClass(elem,i,b, bytes[b]);
			}
		}
		document.body.appendChild(t);
	}
	function loadGeneralInfo(data, info)
	{
		var t = dc("table");
		for (var key in info)
		{
			var row = tr(t);
			td(row,key);
			td(row,info[key]);			
		}
		document.body.appendChild(t);
	}

	function handle(dump)
	{
		var data = dump.data;
		var info = null;
		for(var i = 0; i < identifiers.length && !info; i++)
			info = identifiers[i](data);

		console.log(info);

		loadIntoTable(data, info, false);
		loadIntoTable(data, info, true);
		loadGeneralInfo(data, info.info);

	}
	var noHighlighter = {
		addClass : function(el ,line, byte)
		{
			return;
		}
	};
	var ndefHighligheter = {
		addClass : function(el ,line, byte, value)
		{
			if(line  < 3)
			{
				el.className += " red";
			}
			if ( line == 3)
			{
				console.log(value);
				if( byte == 0 && "e1" == value.toLowerCase())	el.className += " turqoise";
				if( byte == 1 )	el.className += " yellow";
				if( byte == 2 )	el.className += " blue";
				return;
			}
		}
	};
	var mifareHighlighter = {
		addClass : function(el ,line, byte)
		{
			if (line == 0)
			{
				el.className += " blockzero";
			}
			
			if(line < 128){
				linesPerSector = 4;
			} else {
				//Quadruple size sectors
				linesPerSector = 16;
				line = line - 128;
			}

			if(line % linesPerSector == 0)
			{
				el.className += " sectorhdr";
			}
			if(line % linesPerSector == (linesPerSector -1))
			{
				el.className += " sectortrailer";
				if(byte == undefined)
				{
					return;
				}		

				if(byte < 6) el.className += " key_a";
				else if(byte < 10) el.className += " accessconditions";
				else el.className += " key_b";
			}

		}
	};

	</script>
	
</head>
<body></body>
<script>
	var x = { data : 
]]
local skel_2 = [[
			
		};
	handle(x);
	</script>
</html>

]]
local function getHTML(data)
	return skel_1 .. data .. skel_2
end

return {getHTML = getHTML}
