text: var entityMap = require("../maps/entities.json"),
      legacyMap = require("../maps/legacy.json"),
      xmlMap    = require("../maps/xml.json"),
      decodeCodePoint = require("./decode_codepoint.js");
  
  var decodeXMLStrict  = getStrictDecoder(xmlMap),
      decodeHTMLStrict = getStrictDecoder(entityMap);
  
  function getStrictDecoder(map){
  	var keys = Object.keys(map).join("|"),
  	    replace = getReplacer(map);
  
  	keys += "|#[xX][\\da-fA-F]+|#\\d+";
  
  	var re = new RegExp("&(?:" + keys + ");", "g");
  
  	return function(str){
  		return String(str).replace(re, replace);
  	};
  }
  
  var decodeHTML = (function(){
  	var legacy = Object.keys(legacyMap)
  		.sort(sorter);
  
  	var keys = Object.keys(entityMap)
  		.sort(sorter);
  
  	for(var i = 0, j = 0; i < keys.length; i++){
  		if(legacy[j] === keys[i]){
  			keys[i] += ";?";
  			j++;
  		} else {
  			keys[i] += ";";
  		}
  	}
  
  	var re = new RegExp("&(?:" + keys.join("|") + "|#[xX][\\da-fA-F]+;?|#\\d+;?)", "g"),
  	    replace = getReplacer(entityMap);
  
  	function replacer(str){
  		if(str.substr(-1) !== ";") str += ";";
  		return replace(str);
  	}
  
  	//TODO consider creating a merged map
  	return function(str){
  		return String(str).replace(re, replacer);
  	};
  }());
  
  function sorter(a, b){
  	return a < b ? 1 : -1;
  }
  
  function getReplacer(map){
  	return function replace(str){
  		if(str.charAt(1) === "#"){
  			if(str.charAt(2) === "X" || str.charAt(2) === "x"){
  				return decodeCodePoint(parseInt(str.substr(3), 16));
  			}
  			return decodeCodePoint(parseInt(str.substr(2), 10));
  		}
  		return map[str.slice(1, -1)];
  	};
  }
  
  module.exports = {
  	XML: decodeXMLStrict,
  	HTML: decodeHTML,
  	HTMLStrict: decodeHTMLStrict
  };