var org = {p3k: ({url:"http://www.cnbc.com/id/19856705/device/rss/rss.xml", xml:"<?xml version=\"1.0\" encoding=\"utf-8\" ?><?xml-stylesheet type=\"text/xsl\" href=\"http://www.cnbc.com/id/23352264/device/xml/for/cnbcxslt\" ?><!--This is a comment that has been inserted because of the arrogance of IE7 and FireFox 2 developers that have decided that they don't need to honour a xml stylesheet instruction.\tLuckily the designers of these browsers use very brittle sniffing techniques that can be overridden by consuming the first 512 bytes of an xml file. This comment provides these essential 512 bytes of crud and destroys the nice simplicity and cleanliness of my Atom feed. This is a comment that has been inserted because of the arrogance of IE7 and FireFox 2 developers that have decided that they don't need to honour a xml stylesheet instruction. Luckily the designers of these browsers use very brittle sniffing techniques that can be overridden by consuming the first 512 bytes of an xml file. This comment provides these essential 512 bytes of crud and destroys the nice simplicity and cleanliness of my Atom feed. This is a comment that has been inserted because of the arrogance of IE7 and FireFox 2 developers that have decided that they don't need to honour a xml stylesheet instruction. Luckily the designers of these browsers use very brittle sniffing techniques that can be overridden by consuming the first 512 bytes of an xml file. This comment provides these essential 512 bytes of crud and destroys the nice simplicity and cleanliness of my Atom feed.--><rss version=\"2.0\" xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\" ><channel><generator>Workbench</generator><title>CNBC.com Energy Business News</title><link>http://energy.cnbc.com</link><description>CNBC.com Energy Business News</description><language>en</language><copyright></copyright><webMaster>customercare@support.cnbc.com</webMaster><image><url>http://media.cnbc.com/i/CNBC/CNBC_Images/componentbacks/logo_small.gif</url><title>CNBC.com Energy Business News</title><link>http://energy.cnbc.com</link></image><ttl>60</ttl><item><title>Oil Gains as Stock Market Rallies, Ends Near $74</title><metadata:title xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\">Oil Gains as Stock Market Rallies, Ends Near $74</metadata:title><description>Oil rose on Wednesday, rebounding after two days of declines to finish nearly 3 percent higher as strong manufacturing data from China and the United States revived risk appetite and eased worries about flagging energy demand.</description><metadata:description xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\"><![CDATA[<div class=\"rss_image\" style=\"float:left;padding-right:10px;\"><img border=\"0\" vspace=\"0\" hspace=\"0\" src=\"http://media.cnbc.com/j/CNBC/Sections/News_And_Analysis/__Story_Inserts/graphics/__ENERGY/_OIL/oil_barrels_money.ll_featured.jpg\" alt=\"\"></div><div class=\"rss_abstract\" style=\"font:Arial 12px;width:100%;float:left;clear:both\">Oil rose on Wednesday, rebounding after two days of declines to finish nearly 3 percent higher as strong manufacturing data from China and the United States revived risk appetite and eased worries about flagging energy demand.</div>]]></metadata:description><pubDate>Wed, 01 Sep 2010 20:22 GMT</pubDate><guid isPermaLink=\"false\">http://www.cnbc.com//id/38944323</guid><link>http://www.cnbc.com//id/38944323</link></item><item><title>Hurricane Earl Nears East Coast as Islands Evacuate</title><metadata:title xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\">Hurricane Earl Nears East Coast as Islands Evacuate</metadata:title><description></description><metadata:description xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\"><![CDATA[<div class=\"rss_abstract\" style=\"font:Arial 12px;width:100%;float:left;clear:both\"></div>]]></metadata:description><pubDate>Thu, 02 Sep 2010 08:41 GMT</pubDate><guid isPermaLink=\"false\">http://www.cnbc.com//id/38968304</guid><link>http://www.cnbc.com//id/38968304</link></item><item><title>Deepwater Drilling: Government Loses Another Ruling</title><metadata:title xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\">Deepwater Drilling: Government Loses Another Ruling</metadata:title><description></description><metadata:description xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\"><![CDATA[<div class=\"rss_abstract\" style=\"font:Arial 12px;width:100%;float:left;clear:both\"></div>]]></metadata:description><pubDate>Wed, 01 Sep 2010 18:02 GMT</pubDate><guid isPermaLink=\"false\">http://www.cnbc.com//id/38955214</guid><link>http://www.cnbc.com//id/38955214</link></item><item><title>Schork Oil Outlook: Another Crude Supply Surge?</title><metadata:title xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\">Schork Oil Outlook: Another Crude Supply Surge?</metadata:title><description></description><metadata:description xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\"><![CDATA[<div class=\"rss_abstract\" style=\"font:Arial 12px;width:100%;float:left;clear:both\"></div>]]></metadata:description><pubDate>Wed, 01 Sep 2010 16:31 GMT</pubDate><guid isPermaLink=\"false\">http://www.cnbc.com//id/38955120</guid><link>http://www.cnbc.com//id/38955120</link></item><item><title>New Stickers Will Go Beyond MPG in Rating Cars</title><metadata:title xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\">New Stickers Will Go Beyond MPG in Rating Cars</metadata:title><description></description><metadata:description xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\"><![CDATA[<div class=\"rss_abstract\" style=\"font:Arial 12px;width:100%;float:left;clear:both\"></div>]]></metadata:description><pubDate>Tue, 31 Aug 2010 12:12 GMT</pubDate><guid isPermaLink=\"false\">http://www.cnbc.com//id/38931461</guid><link>http://www.cnbc.com//id/38931461</link></item><item><title>What Do Cream Cheese, Solar Panels Have In Common?</title><metadata:title xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\">What Do Cream Cheese, Solar Panels Have In Common?</metadata:title><description></description><metadata:description xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\"><![CDATA[<div class=\"rss_abstract\" style=\"font:Arial 12px;width:100%;float:left;clear:both\"></div>]]></metadata:description><pubDate>Tue, 31 Aug 2010 13:29 GMT</pubDate><guid isPermaLink=\"false\">http://www.cnbc.com//id/38932417</guid><link>http://www.cnbc.com//id/38932417</link></item><item><title>Latest Thing to Get 'Green': Champagne Bottles</title><metadata:title xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\">Latest Thing to Get 'Green': Champagne Bottles</metadata:title><description></description><metadata:description xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\"><![CDATA[<div class=\"rss_abstract\" style=\"font:Arial 12px;width:100%;float:left;clear:both\"></div>]]></metadata:description><pubDate>Wed, 01 Sep 2010 12:59 GMT</pubDate><guid isPermaLink=\"false\">http://www.cnbc.com//id/38950998</guid><link>http://www.cnbc.com//id/38950998</link></item><item><title>Special Report: Katrina, Five Years Later</title><metadata:title xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\">Special Report: Katrina, Five Years Later</metadata:title><description></description><metadata:description xmlns:metadata=\"http://search.cnbc.com/rss/2.0/modules/siteContentMetadata\"><![CDATA[<div class=\"rss_image\" style=\"float:left;padding-right:10px;\"><img border=\"0\" vspace=\"0\" hspace=\"0\" src=\"http://msnbcmedia.msn.com/i/CNBC/Sections/News_And_Analysis/__Story_Inserts/graphics/__PILLS_ALLEN/news_bug_only_green.gif\" alt=\"\"></div><div class=\"rss_abstract\" style=\"font:Arial 12px;width:100%;float:left;clear:both\"></div>]]></metadata:description><pubDate>Wed, 25 Aug 2010 18:47 GMT</pubDate><guid isPermaLink=\"false\">http://www.cnbc.com//id/38815295</guid><link>http://www.cnbc.com//id/38815295</link></item></channel></rss>\n", message:undefined, modified:(new Date(1283438349800)), baseUri:"http://p3k.org/rss/", query:"frameColor=black&textColor=white&_=1236410769399&titleBarColor=gray&compact=&fontFace=&align=center&showXmlButton=true&maxItems=3&boxFillColor=black&titleBarTextColor=black&width=480&url=http://www.cnbc.com/id/19856705/device/rss/rss.xml&", param:{textColor:"white", width:"480", align:"center", fontFace:"", url:"http://www.cnbc.com/id/19856705/device/rss/rss.xml", compact:"", frameColor:"black", showXmlButton:"true", boxFillColor:"black", _:"1236410769399", titleBarColor:"gray", maxItems:"3", titleBarTextColor:"black"}, box:"<table class=\"rssBox\" width=\"${width}\" bgcolor=\"${frameColor}\" \n      style=\"table-layout: fixed; overflow: hidden; font-family: ${fontFace};\" \n      align=\"${align}\" cellspacing=\"1\" cellpadding=\"7\" border=\"0\">\n<tr bgcolor=\"${titleBarColor}\">\n<td>\n   ${xmlButton}\n   <strong>${title}</strong>\n   <div>\n      <small style=\"color: ${titleBarTextColor};\">${date}</small>\n   </div>\n</td>\n</tr>\n<tr bgcolor=\"${boxFillColor}\">\n<td class=\"rssBoxContent\" style=\"color: ${textColor};\">\n   ${image}\n   ${items}\n   ${input}\n   <div class=\"rssBoxPromo\" style=\"margin-top: 0px; text-align: left; \n         font: 9px verdana, sans-serif\">\n      RSS box by <a href=\"http://p3k.org/rss\">p3k.org</a>.\n   </div>\n</td>\n</tr>\n</table>\n\n", image:"<a href=\"${link}\"><img src=\"${source}\" width=\"${width}\" height=\"${height}\" \nalt=\"${title}\" title=\"${title}\" align=\"${align}\" valign=\"${valign}\" \nhspace=\"${hspace}\" vspace=\"${vspace}\" border=\"0\" /></a>\n\n", input:"<form method=\"get\" action=\"${link}\">\n${description}\n<input type=\"text\" name=\"${name}\" size=\"15\" /> <input type=\"submit\" \nvalue=\"${title}\" />\n</form>\n\n", item:"<div class=\"rssBoxItemContent\">\n${title}\n${break}\n${description}\n${buttons}\n</div><br />\n\n", date:"${year}-${month}-${day}, ${hours}:${minutes}h\n\n", link:"<a class=\"${class}\" href=\"${link}\" style=\"${style}\">${text}</a>\n", error:"<?xml version=\"1.0\"?>\n<rss version=\"error\">\n   <channel>\n      <title>RSS Box Error</title>\n      <link>${link}</link>\n      <description>This output was automatically generated to report an error \n      that occurred during a request to the JavaScript RSS Box Viewer.</description>\n      <item>\n         <title>Oops, something went wrong...</title>\n         <description>An error occurred while processing the request to the \n         JavaScript RSS Box Viewer.</description>\n      </item>\n      <item>\n         <title>An error message was returned by the server.</title>\n         <description>${message}</description>\n      </item>\n      <item>\n         <description>Most likely, this might have happened because of a \n         non-existent or invalid RSS feed URL. Please check and possibly correct \n         your input, then try again.</description>\n      </item>\n   </channel>\n</rss>\n\n"})};
function debug(str) {
   return document.write('<p><span style="background-color: yellow;">', 
         str, '</span><p>');
}

org.p3k.RssBox = function() {
   var ref;
   var ISOPATTERN = /([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9:]+).*$/;
   
   var data = org.p3k;
   data.defaults = {
      url: "http://blog.p3k.org/rss",
      maxItems: 7,
      width: 200,
      align: "",
      frameColor: "black",
      titleBarColor: "lightblue",
      titleBarTextColor: "black",
      boxFillColor: "white",
      textColor: "black",
      showXmlButton: "",
      compact: ""
   };
   
   var baseUri = data.baseUri;
    
   var getColor = function(str) {
      if (str.length === 6 && parseInt(str, 16) && str.indexOf("#") !== 0) {
         str = "#" + str;
      }
      return str.toLowerCase();
   }

   var value;
   for (var i in data.defaults) {
      value = data.param[i];
      if (!value || value.length === 0) {
         data.param[i] = data.defaults[i];
      } else if (i.indexOf("Color") > 0) {
         data.param[i] = getColor(value);
      }
   }

   // FIXME: Ugly work-around for many boxes using too small width 
   // values because the former version did not show the exact output.
   if (data.param.javascript && data.param.width < 200) {
      data.param.width = 200;
   }
   // Remove obsolete parameters from param and query
   delete data.param.javascript;
   data.query = data.query.replace("javascript=true", "");   

   var NAMESPACES = {
      dc: "http://purl.org/dc/elements/1.1/",
      rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   };

   var getUrl = function(url) {
      url = baseUri + "proxy.r?" + encodeURIComponent(url);
   
      var HttpRequest = function() {
         return (typeof XMLHttpRequest !== "undefined") ?
            new XMLHttpRequest() : new ActiveXObject("Msxml2.XMLHTTP");
      }
   
      var request = new HttpRequest();
      request.open("GET", url, false);
      request.send(null);   
      if (!request.getResponseHeader("Date")) {
         var cached = request;
         var ifModifiedSince = cached.getResponseHeader("Last-Modified") || 
               new Date(0); // January 1, 1970
         request = new HttpRequest();
         request.open("GET", url, false);
         request.setRequestHeader("If-Modified-Since", ifModifiedSince);
         request.send("");
         if (request.status === 304) {
            request = cached; 
         }
      }
      return request;
   }
   
   var getDocument = function(source) {
      if (source) {
         if (document.implementation.createDocument) {
            var parser = new DOMParser();
            var doc = parser.parseFromString(source, "text/xml");
            return doc;
         } else if (window.ActiveXObject) {
            var doc = new ActiveXObject("Microsoft.XMLDOM");
            doc.async = "false";
            doc.loadXML(source);
            return doc;
         }
      }
      return null;
   }
   
   var getError = function() {
      var msg = null, root;
      if (!xml || data.message) {
         msg = data.message || "Unknown error.";
      } else if (xml.parseError && xml.parseError.errorCode) {
         msg = xml.parseError.reason; // IExplore
      } else if (root = xml.documentElement) {
         var errorNode;
         if (root.nodeName === "parsererror") {
            msg = xml.documentElement.textContent; // Mozilla
         } else if ((errorNode = root.childNodes[0]) && 
               errorNode.nodeName === "parsererror") {
            msg = errorNode.textContent; // Safari
         } else if (!/rss|rdf|scriptingNews/i.test(xml.documentElement.nodeName)) {
            msg = "Incompatible data format. Are you sure this is an RSS feed?";
         }
      }
      return msg;
   }
   
   var getNode = function(parent, name, namespace) {
      if (namespace) {
         if (typeof parent.getElementsByTagNameNS === "undefined") {
            var elements = parent.getElementsByTagName(namespace + ":" + name);
         } else {
            var elements = parent.getElementsByTagNameNS(NAMESPACES[namespace], name);
         }
      } else {
         var elements = parent.getElementsByTagName(name);
      }
      if (elements && elements[0]) {
         return elements[0];
      }
      return null;
   }
   
   var getText = function(node) {
      if (node && node.childNodes && node.childNodes.length > 0) {
         return node.childNodes[0].nodeValue || "";
      }
      return "";
   }
   
   var trim = function(str) {
      if (str) {
         return str.replace(/^\s*(\S*)\s*$/, "$1");
      }
      return "";
   }
   
   var padZero = function(n) {
      if (n < 10) {
         return "0" + n
      }
      return n;
   }

   var encodeXml = function(str) {
      if (!str) {
         return "";
      }
      return str.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/&/g, "&amp;");
   }
      
   var render = function(template, param) {
      if (!template || !param) {
         return template;
      }
      template = template.replace(/\$\{([^}]+)\}/g, function() {
         var key = arguments[1];
         return param[key] || "";
      });
      return template;
   }
   
   var renderDate = function(date) {
      if (date.constructor !== Date) {
         var str = String(date);
         var millis = Date.parse(str.replace(ISOPATTERN, "$1/$2/$3 $4"));
         if (millis) {
            date = new Date(millis);
         } else {
            date = new Date;
         }
      }

      return render(data.date, {
         year: date.getFullYear(),
         month: padZero(date.getMonth() + 1),
         day: padZero(date.getDate()),
         hours: padZero(date.getHours()),
         minutes: padZero(date.getMinutes()),
         seconds: padZero(date.getSeconds()),
         timeZone: "" // date.getTimezoneOffset()
      });
   }
   
   var renderButtons = function(enclosure, source) {
      var result = "";
      if (enclosure && enclosure.link) {
         result += render(data.image, {
            source: baseUri + "enclosure.gif",
            title: enclosure.type,
            link: encodeURI(enclosure.link),
            width: 13,
            height: 16
         });
      }
      if (source && source.link) {
         result += render(data.image, {
            source: baseUri + "source.gif",
            title: source.title,
            link: encodeURI(source.link),
            width: 15,
            height: 15
         });
      }
      return result;         
   }
   
   var param = data.param;
   var rss = data.rss = {items: []};
   var xml = getDocument(data.xml);

   rss.error = getError();
   if (rss.error !== null) {
      xml = getDocument(render(data.error, {
         link: baseUri + "?" + encodeXml(data.query),
         message: encodeXml(rss.error)
      }));
      param.compact = 0;
      param.showXmlButton = 1;
   }

   var root = xml.documentElement;
   var type = root.nodeName;

   if (type === "scriptingNews") {
      var channel = getNode(xml, "header");
      rss.format = "Scripting News";
      rss.version = getText(getNode(channel, "scriptingNewsVersion"));
      rss.title = getText(getNode(channel, "channelTitle"));
      rss.description = getText(getNode(channel, "channelDescription"));
      rss.link = getText(getNode(channel, "channelLink"));
      if (ref = getText(getNode(channel, "imageUrl"))) {
         ref = rss.image = {source: ref};
         ref.title = getText(getNode(channel, "imageTitle"));
         ref.link = getText(getNode(channel, "imageLink"));
         ref.width = getText(getNode(channel, "imageWidth"));
         ref.height = getText(getNode(channel, "imageHeight"));
         ref.description = getText(getNode(channel, "imageCaption"));
      }
   } else {
      var channel = getNode(xml, "channel");
      rss.format = "RSS";
      rss.version = (type === "rdf:RDF") ? "1.0" : 
            root.getAttribute("version");
      rss.title = getText(getNode(channel, "title"));
      rss.description = getText(getNode(channel, "description"));
      rss.link = getText(getNode(channel, "link"));
      var image = getNode(xml, "image");
      if (image) {
         ref = rss.image = {};
         ref.source = getText(getNode(image, "url"));
         ref.title = getText(getNode(image, "title"));
         ref.link = getText(getNode(image, "link"));
         ref.width = getText(getNode(image, "width"));
         ref.height = getText(getNode(image, "height"));
         ref.description = getText(getNode(image, "description"));
      }
   }
   
   if (type === "rdf:RDF") {
      rss.date = renderDate(getText(getNode(channel, "date", "dc")) || data.modified);
      rss.rights = getText(getNode(channel, "creator", "dc"));
      var input = getNode(root, "textinput");
      if (input && !getNode(input, "link")) {
         input = root.getElementsByTagName("textinput")[1];
      }
      if (input) {
         ref = rss.input = {};
         ref.link = getText(getNode(input, "link"));
         ref.description = getText(getNode(input, "description"));
         ref.name = getText(getNode(input, "name"));
         ref.title = getText(getNode(input, "title"));
      }
   } else {
      rss.date = renderDate(getText(getNode(channel, "lastBuildDate") || getText(getNode(channel, "pubDate"))) || data.modified);
      rss.rights = getText(getNode(channel, "copyright"));
   }
   
   var item, text, node;
   var items = xml.getElementsByTagName("item");

   for (var i=0; i<Math.min(items.length, param.maxItems); i+=1) {
      item = items[i];

      if (type === "scriptingNews") {
         ref = {title: ""};
         ref.description = getText(getNode(item, "text")).replace(/\n/g, " ");
         ref.link = getText(getNode(item, "link"));
         if (text = trim(getText(getNode(item, "linetext")).replace(/\n/g, " "))) {
            ref.description = ref.description.replace(new RegExp(text), 
                  '<a href="' + getText(getNode(item, "url")) + '">' + text + '</a>');
         }
      } else {
         ref = {
            title: getText(getNode(item, "title")),
            description: getText(getNode(item, "description")),
            link: getText(getNode(item, "link") || getNode(item, "guid"))
         };
     }

     if (node = getNode(item, "source")) {
        ref.source = {
           link: node.getAttribute("url"),
           title: getText(node)
        }
     }
     
     if (node = getNode(item, "enclosure")) {
        ref.enclosure = {
           link: node.getAttribute("url"),
           length: node.getAttribute("length"),
           type: node.getAttribute("type")
        }
     }
     
     if (node = getNode(item, "category")) {
        ref.category = {
           domain: node.getAttribute("domain") || "",
           content: getText(node)
        }
     }
     
     rss.items.push(ref);
   }
   
   var item, items = "";
   for (var i=0; i<rss.items.length; i+=1) {
      item = rss.items[i];
      items += render(data.item, {
         title: new function() {
            var title = (!param.compact ? "<strong>" : "");
            if (item.link) {
               title += render(data.link, {
                  link: encodeURI(item.link),
                  text: item.title,
                  'class': "rssBoxItemTitle"
               });
            } else {
               title += item.title;
            }
            !param.compact && (title += "</strong>");
            return new String(title); // FIXME: Funny, title alone will be rendered as [object]
         }(),
         'break': item.title && item.description ? "<br />" : "",
         description: (!param.compact || !item.title) && item.description,
         buttons: renderButtons(item.enclosure, item.source)
      });
   }
   
   var box = render(data.box, {
      title: rss.link ? render(data.link, {
         link: encodeURI(rss.link),
         text: rss.title,
         'class': "rssBoxTitle",
         style: "color: " + param.titleBarTextColor
      }) : rss.title,
      description: rss.description,
      items: items,

      xmlButton: param.showXmlButton && render(data.image, {
         link: param.url,
         source: baseUri + "rss.png",
         title: rss.format + " " + rss.version,
         width: 16,
         height: 16,
         align: "right",
         hspace: 3
      }),
      
      image: !param.compact && rss.image && render(data.image, {
         link: encodeURI(rss.image.link),
         source: rss.image.source,
         width: rss.image.width,
         height: rss.image.height,
         title: rss.image.title,
         align: "right",
         valign: "baseline",
         hspace: 5,
         vspace: 5
      }),
      
      input: !param.compact && rss.input && render(data.input, {
         link: encodeURI(rss.input.link),
         description: rss.input.description,
         name: rss.input.name,
         title: rss.input.title
      }),
      
      date: rss.date,
      width: param.width,
      frameColor: param.frameColor,
      fontFace: param.fontFace,
      align: param.align,
      titleBarColor: param.titleBarColor,
      titleBarTextColor: param.titleBarTextColor,
      boxFillColor: param.boxFillColor,
      textColor: param.textColor
   });

   if (!window.rssBoxSetup) {
      document.write(box);
   }
   
   return box;
};

org.p3k.RssBox();

