<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Brandon Sterne &#187; Web Development</title>
	<atom:link href="http://brandon.sternefamily.net/posts/category/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://brandon.sternefamily.net/posts</link>
	<description>The Whole Brevity Thing</description>
	<lastBuildDate>Mon, 14 Mar 2011 22:52:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Update to CSP Bookmarklet</title>
		<link>http://brandon.sternefamily.net/posts/2011/01/update-to-csp-bookmarklet/</link>
		<comments>http://brandon.sternefamily.net/posts/2011/01/update-to-csp-bookmarklet/#comments</comments>
		<pubDate>Thu, 20 Jan 2011 16:43:10 +0000</pubDate>
		<dc:creator>bsterne</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://brandon.sternefamily.net/posts/?p=434</guid>
		<description><![CDATA[It was pointed out to me that my CSP bookmarklet was using a feature added in ECMAScript 5, Object.keys, and thus did not work in older browsers. I added a bit of code to address this: Object.keys = Object.keys &#124;&#124; function(obj) { var keys = []; for (var key in obj) { if (obj.hasOwnProperty(key)) keys.push(key); [...]]]></description>
			<content:encoded><![CDATA[<p>It was pointed out to me that my <a href="/posts/2010/10/content-security-policy-recommendation-bookmarklet/">CSP bookmarklet</a> was using a feature added in ECMAScript 5, <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys">Object.keys</a>, and thus did not work in older browsers.  I added a bit of code to address this:</p>
<pre class="brush: javascript; gutter: false">
Object.keys = Object.keys || function(obj) {
  var keys = [];
  for (var key in obj) {
    if (obj.hasOwnProperty(key))
      keys.push(key);
  }
  return keys;
}</pre>
<p>Browsers that don&#8217;t natively support <code>Object.keys</code> will now have that functionality added when the bookmarklet runs.  Go ahead, give it a try: <a href="javascript:function%20getElements%28tags%29%7Bvar%20arr%3D%5B%5D%3Btags%3Dtags.split%28%22%2C%22%29%3Bfor%28var%20i%3D0%3Bi%3Ctags.length%3Bi%2B%2B%29%7Bvar%20elems%3Ddocument.getElementsByTagName%28tags%5Bi%5D%29%3Bfor%28var%20j%3D0%3Bj%3Celems.length%3Bj%2B%2B%29arr.push%28elems%5Bj%5D%29%7D%0Areturn%20arr%3B%7D%0Afunction%20parseUri%28str%29%7Bvar%20o%3DparseUri.options%2Cm%3Do.parser%5Bo.strictMode%3F%22strict%22%3A%22loose%22%5D.exec%28str%29%2Curi%3D%7B%7D%2Ci%3D14%3Bwhile%28i--%29uri%5Bo.key%5Bi%5D%5D%3Dm%5Bi%5D%7C%7C%22%22%3Buri%5Bo.q.name%5D%3D%7B%7D%3Buri%5Bo.key%5B12%5D%5D.replace%28o.q.parser%2Cfunction%28%240%2C%241%2C%242%29%7Bif%28%241%29uri%5Bo.q.name%5D%5B%241%5D%3D%242%3B%7D%29%3Breturn%20uri%3B%7D%3BparseUri.options%3D%7BstrictMode%3Afalse%2Ckey%3A%5B%22source%22%2C%22protocol%22%2C%22authority%22%2C%22userInfo%22%2C%22user%22%2C%22password%22%2C%22host%22%2C%22port%22%2C%22relative%22%2C%22path%22%2C%22directory%22%2C%22file%22%2C%22query%22%2C%22anchor%22%5D%2Cq%3A%7Bname%3A%22queryKey%22%2Cparser%3A/%28%3F%3A%5E%7C%26%29%28%5B%5E%26%3D%5D%2A%29%3D%3F%28%5B%5E%26%5D%2A%29/g%7D%2Cparser%3A%7Bstrict%3A/%5E%28%3F%3A%28%5B%5E%3A%5C/%3F%23%5D%2B%29%3A%29%3F%28%3F%3A%5C/%5C/%28%28%3F%3A%28%28%5B%5E%3A%40%5D%2A%29%28%3F%3A%3A%28%5B%5E%3A%40%5D%2A%29%29%3F%29%3F%40%29%3F%28%5B%5E%3A%5C/%3F%23%5D%2A%29%28%3F%3A%3A%28%5Cd%2A%29%29%3F%29%29%3F%28%28%28%28%3F%3A%5B%5E%3F%23%5C/%5D%2A%5C/%29%2A%29%28%5B%5E%3F%23%5D%2A%29%29%28%3F%3A%5C%3F%28%5B%5E%23%5D%2A%29%29%3F%28%3F%3A%23%28.%2A%29%29%3F%29/%2Cloose%3A/%5E%28%3F%3A%28%3F%21%5B%5E%3A%40%5D%2B%3A%5B%5E%3A%40%5C/%5D%2A%40%29%28%5B%5E%3A%5C/%3F%23.%5D%2B%29%3A%29%3F%28%3F%3A%5C/%5C/%29%3F%28%28%3F%3A%28%28%5B%5E%3A%40%5D%2A%29%28%3F%3A%3A%28%5B%5E%3A%40%5D%2A%29%29%3F%29%3F%40%29%3F%28%5B%5E%3A%5C/%3F%23%5D%2A%29%28%3F%3A%3A%28%5Cd%2A%29%29%3F%29%28%28%28%5C/%28%3F%3A%5B%5E%3F%23%5D%28%3F%21%5B%5E%3F%23%5C/%5D%2A%5C.%5B%5E%3F%23%5C/.%5D%2B%28%3F%3A%5B%3F%23%5D%7C%24%29%29%29%2A%5C/%3F%29%3F%28%5B%5E%3F%23%5C/%5D%2A%29%29%28%3F%3A%5C%3F%28%5B%5E%23%5D%2A%29%29%3F%28%3F%3A%23%28.%2A%29%29%3F%29/%7D%7D%3Bvar%20sources%3D%7B%27images%27%3A%7B%7D%2C%27media%27%3A%7B%7D%2C%27script%27%3A%7B%7D%2C%27object%27%3A%7B%7D%2C%27frame%27%3A%7B%7D%2C%27font%27%3A%7B%7D%2C%27style%27%3A%7B%7D%7D%3Bvar%20directives%3D%7B%27images%27%3A%27img-src%27%2C%27media%27%3A%27media-src%27%2C%27script%27%3A%27script-src%27%2C%27object%27%3A%27object-src%27%2C%27frame%27%3A%27frame-src%27%2C%27font%27%3A%27font-src%27%2C%27style%27%3A%27style-src%27%7D%3Bvar%20violations%3D%5B%5D%3Bfunction%20capWord%28w%29%7Breturn%20w.charAt%280%29.toUpperCase%28%29%2Bw.slice%281%29%3B%7D%0Afunction%20objIsEmpty%28obj%29%7Bfor%28var%20prop%20in%20obj%29%7Bif%28obj.hasOwnProperty%28prop%29%29%0Areturn%20false%3B%7D%0Areturn%20true%3B%7D%0Afunction%20generatePolicyFromSources%28sourceList%2Cviolations%29%7Bvar%20policy%3D%22Recommended%20Policy%3A%5Cn%22%3Bpolicy%2B%3D%22allow%20%27self%27%3B%22%3Bfor%28type%20in%20sourceList%29%7Bif%28objIsEmpty%28sourceList%5Btype%5D%29%29%0Acontinue%3Bpolicy%2B%3D%22%20%22%2Bdirectives%5Btype%5D%2B%22%20%22%2B%0AObject.keys%28sourceList%5Btype%5D%29.join%28%22%20%22%29%2B%22%3B%22%3B%7D%0Aif%28violations.length%29%7Bpolicy%2B%3D%22%5Cn%5Cn%22%3Bpolicy%2B%3D%28violations.length%3D%3D1%29%3F%22Inline%20Script%20Violation%3A%22%3A%22Inline%20Script%20Violations%3A%22%3Bfor%28var%20v%3D0%3Bv%3Cviolations.length%3Bv%2B%2B%29%0Apolicy%2B%3D%22%5Cn%22%2B%28v%2B1%29%2B%22%3A%20%22%2Bviolations%5Bv%5D%3B%7D%0Areturn%20policy%3B%7D%0AObject.keys%3DObject.keys%7C%7Cfunction%28obj%29%7Bvar%20keys%3D%5B%5D%3Bfor%28var%20key%20in%20obj%29%7Bif%28obj.hasOwnProperty%28key%29%29%0Akeys.push%28key%29%3B%7D%0Areturn%20keys%3B%7D%0Afunction%20analyzeContent%28%29%7Bvar%20myHost%3DparseUri%28window.location.href%29.host%3Bvar%20images%3DgetElements%28%22img%22%29%3Bfor%28var%20i%3D0%3Bi%3Cimages.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28images%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.images%29%29%0Asources.images%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.images%29%29%0Asources.images%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20linkElems%3DgetElements%28%22link%22%29%3Bfor%28var%20i%3D0%3Bi%3ClinkElems.length%3Bi%2B%2B%29%7Bif%28linkElems%5Bi%5D.getAttribute%28%22rel%22%29%3D%3D%22shortcut%20icon%22%29%7Bvar%20uriParts%3DparseUri%28linkElems%5Bi%5D.href%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.images%29%29%0Asources.images%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.images%29%29%0Asources.images%5Bhost%5D%3Dnull%3B%7D%7D%7D%0Avar%20media%3DgetElements%28%22video%2Caudio%22%29%3Bfor%28var%20i%3D0%3Bi%3Cmedia.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28media%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.media%29%29%0Asources.media%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.media%29%29%0Asources.media%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20scripts%3DgetElements%28%22script%22%29%3Bfor%28var%20i%3D0%3Bi%3Cscripts.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28scripts%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.script%29%29%0Asources.script%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.script%29%29%0Asources.script%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20objAppl%3DgetElements%28%22object%2Capplet%22%29%3Bfor%28var%20i%3D0%3Bi%3CobjAppl.length%3Bi%2B%2B%29%7Bif%28objAppl%5Bi%5D.hasAttribute%28%22codebase%22%29%29%7Bvar%20uriParts%3DparseUri%28objAppl%5Bi%5D.getAttribute%28%22codebase%22%29%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%0Aif%28objAppl%5Bi%5D.hasAttribute%28%22classid%22%29%29%7Bvar%20uriParts%3DparseUri%28objAppl%5Bi%5D.getAttribute%28%22classid%22%29%29%3Bif%28%5B%22http%22%2C%22https%22%2C%22ftp%22%2Cnull%5D.indexOf%28uriParts%5B%22protocol%22%5D%29%21%3D-1%29%7Bvar%20host%3DuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%7D%0Aif%28objAppl%5Bi%5D.hasAttribute%28%22data%22%29%29%7Bvar%20uriParts%3DparseUri%28objAppl%5Bi%5D.getAttribute%28%22data%22%29%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%0Aif%28objAppl%5Bi%5D.hasAttribute%28%22archive%22%29%29%7Bvar%20uriParts%3DparseUri%28objAppl%5Bi%5D.getAttribute%28%22archive%22%29%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%7D%0Avar%20embeds%3DgetElements%28%22embed%22%29%3Bfor%28var%20i%3D0%3Bi%3Cembeds.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28embeds%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20frameElems%3DgetElements%28%22frame%2Ciframe%22%29%3Bfor%28var%20i%3D0%3Bi%3CframeElems.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28frameElems%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.frame%29%29%0Asources.frame%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.frame%29%29%0Asources.frame%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20stylesheets%3D%7B%7D%3Btry%7Bvar%20stylesheets%3Ddocument.styleSheets%3B%7D%0Acatch%28e%29%7B%7D%0Afor%28var%20i%3D0%3Bi%3Cstylesheets.length%3Bi%2B%2B%29%7Bvar%20rules%3D%7B%7D%3Btry%7Brules%3Dstylesheets%5Bi%5D.cssRules%3B%7D%0Acatch%28e%29%7Bcontinue%3B%7D%0Aif%28%21rules%29%7Bcontinue%3B%7D%0Afor%28var%20j%3D0%3Bj%3Crules.length%3Bj%2B%2B%29%7Bif%28rules%5Bj%5D.type%3D%3Drules%5Bj%5D.FONT_FACE_RULE%29%7Bvar%20src%3Drules%5Bj%5D.style.getPropertyValue%28%22src%22%29%3Bif%28src%29%7Bvar%20url%3Dsrc.replace%28/%5Eurl%5B%27%22%5D%2A/%2C%22%22%29.replace%28/%5B%27%22%5D%2A%5C%29%24/%2C%22%22%29%3Bvar%20uriParts%3DparseUri%28url%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.font%29%29%0Asources.font%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.font%29%29%0Asources.font%5Bhost%5D%3Dnull%3B%7D%7D%7D%7D%7D%0Avar%20linkElems%3DgetElements%28%22link%22%29%3Bfor%28var%20i%3D0%3Bi%3ClinkElems.length%3Bi%2B%2B%29%7Bif%28linkElems%5Bi%5D.getAttribute%28%22rel%22%29%3D%3D%22stylesheet%22%29%7Bvar%20uriParts%3DparseUri%28linkElems%5Bi%5D.href%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.style%29%29%0Asources.style%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.style%29%29%0Asources.style%5Bhost%5D%3Dnull%3B%7D%7D%7D%0Avar%20allElems%3DgetElements%28%22%2A%22%29%3Bfor%28var%20e%3D0%3Be%3CallElems.length%3Be%2B%2B%29%7Bvar%20elem%3DallElems%5Be%5D%3Bvar%20attrs%3D%5B%5D%3Bfor%28var%20key%20in%20elem.attributes%29%7Bif%28%21isNaN%28key%29%29%7Battrs.push%28elem.attributes%5Bkey%5D.name%29%3B%7D%7D%0Afor%28var%20i%3D0%3Bi%3Cattrs.length%3Bi%2B%2B%29%7Bif%28attrs%5Bi%5D.match%28/%5Eon/%29%29%7Bvar%20attr_pairs%3D%5B%5D%0Afor%28var%20j%3D0%3Bj%3Cattrs.length%3Bj%2B%2B%29%7Bvar%20attr_val%3Delem.attributes%5Battrs%5Bj%5D%5D.nodeValue.replace%28/%5Cs%2B/g%2C%22%20%22%29%3Battr_pairs.push%28attrs%5Bj%5D%2B%27%3D%22%27%2Battr_val%2B%27%22%27%29%3B%7D%0Avar%20error%3Dattrs%5Bi%5D%2B%22%20on%20element%20%3C%22%2Belem.nodeName%2B%22%20%22%2B%0Aattr_pairs.join%28%22%20%22%29%2B%22%3E%22%3Bviolations.push%28%22event%20handling%20attribute%3A%20%22%2Berror%29%3B%7D%7D%0Aif%28elem.nodeName%3D%3D%3D%22SCRIPT%22%26%26elem.text.length%29%7Bvar%20script%3D%28elem.text.length%3E100%29%3Felem.text.substr%280%2C100%29%2B%22%20...%20%22%3Aelem.text%3Bviolations.push%28%22internal%20script%20node%3A%20%22%2Bscript%29%3B%7D%7D%0Aalert%28generatePolicyFromSources%28sources%2Cviolations%29%29%3B%7D%0AanalyzeContent%28%29%3B" class="bookmarklet">Recommend CSP</a></p>
<p>As before, the <a href="https://github.com/bsterne/bsterne-tools/blob/master/csp-bookmarklet/csp-bookmarklet.js">full source</a> is posted for you to browse as well.</p>
<p><script type="text/javascript" src="/posts/syntax/src/shCore.js"></script><br />
<script type="text/javascript" src="/posts/syntax/scripts/shBrushJScript.js"></script></p>
<link rel="stylesheet" type="text/css" href="/posts/syntax/styles/shCore.css" />
<link type="text/css" rel="Stylesheet" href="/posts/syntax/styles/shThemeDefault.css"/>
<script type="text/javascript">SyntaxHighlighter.all()</script></p>
<style type="text/css">
a.bookmarklet {
  text-decoration: none;
  display: inline-block;
  border: 1px solid #bbb;
  padding: .25em .5em;
  margin: .5em;
  -moz-border-radius: .5em;
  -webkit-border-radius: .5em;
}
</style>
]]></content:encoded>
			<wfw:commentRss>http://brandon.sternefamily.net/posts/2011/01/update-to-csp-bookmarklet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Content Security Policy Recommendation Bookmarklet</title>
		<link>http://brandon.sternefamily.net/posts/2010/10/content-security-policy-recommendation-bookmarklet/</link>
		<comments>http://brandon.sternefamily.net/posts/2010/10/content-security-policy-recommendation-bookmarklet/#comments</comments>
		<pubDate>Thu, 14 Oct 2010 23:02:51 +0000</pubDate>
		<dc:creator>bsterne</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://brandon.sternefamily.net/posts/?p=414</guid>
		<description><![CDATA[I wrote a bookmarklet that analyzes the content on the current page and recommends a Content Security Policy based on the types of content it finds on the page and the sources of that content. The implementation also takes into account resources that are dynamically added to the page by JavaScript. For instance, today I [...]]]></description>
			<content:encoded><![CDATA[<p>I wrote a bookmarklet that analyzes the content on the current page and recommends a Content Security Policy based on the types of content it finds on the page and the sources of that content.  The implementation also takes into account resources that are dynamically added to the page by JavaScript.</p>
<p style="margin:1em">For instance, today I learned that ReCAPTCHA loads script both from api.recaptcha.net, but also from www.google.com.  <em>Note to self: figure out why Google needs to know about every ReCAPTCHA load.</em></p>
<p>You can test it out by clicking the following bookmarklet: <a href="javascript:function%20getElements%28tags%29%7Bvar%20arr%3D%5B%5D%3Btags%3Dtags.split%28%22%2C%22%29%3Bfor%28var%20i%3D0%3Bi%3Ctags.length%3Bi%2B%2B%29%7Bvar%20elems%3Ddocument.getElementsByTagName%28tags%5Bi%5D%29%3Bfor%28var%20j%3D0%3Bj%3Celems.length%3Bj%2B%2B%29arr.push%28elems%5Bj%5D%29%7D%0Areturn%20arr%3B%7D%0Afunction%20parseUri%28str%29%7Bvar%20o%3DparseUri.options%2Cm%3Do.parser%5Bo.strictMode%3F%22strict%22%3A%22loose%22%5D.exec%28str%29%2Curi%3D%7B%7D%2Ci%3D14%3Bwhile%28i--%29uri%5Bo.key%5Bi%5D%5D%3Dm%5Bi%5D%7C%7C%22%22%3Buri%5Bo.q.name%5D%3D%7B%7D%3Buri%5Bo.key%5B12%5D%5D.replace%28o.q.parser%2Cfunction%28%240%2C%241%2C%242%29%7Bif%28%241%29uri%5Bo.q.name%5D%5B%241%5D%3D%242%3B%7D%29%3Breturn%20uri%3B%7D%3BparseUri.options%3D%7BstrictMode%3Afalse%2Ckey%3A%5B%22source%22%2C%22protocol%22%2C%22authority%22%2C%22userInfo%22%2C%22user%22%2C%22password%22%2C%22host%22%2C%22port%22%2C%22relative%22%2C%22path%22%2C%22directory%22%2C%22file%22%2C%22query%22%2C%22anchor%22%5D%2Cq%3A%7Bname%3A%22queryKey%22%2Cparser%3A/%28%3F%3A%5E%7C%26%29%28%5B%5E%26%3D%5D%2A%29%3D%3F%28%5B%5E%26%5D%2A%29/g%7D%2Cparser%3A%7Bstrict%3A/%5E%28%3F%3A%28%5B%5E%3A%5C/%3F%23%5D%2B%29%3A%29%3F%28%3F%3A%5C/%5C/%28%28%3F%3A%28%28%5B%5E%3A%40%5D%2A%29%28%3F%3A%3A%28%5B%5E%3A%40%5D%2A%29%29%3F%29%3F%40%29%3F%28%5B%5E%3A%5C/%3F%23%5D%2A%29%28%3F%3A%3A%28%5Cd%2A%29%29%3F%29%29%3F%28%28%28%28%3F%3A%5B%5E%3F%23%5C/%5D%2A%5C/%29%2A%29%28%5B%5E%3F%23%5D%2A%29%29%28%3F%3A%5C%3F%28%5B%5E%23%5D%2A%29%29%3F%28%3F%3A%23%28.%2A%29%29%3F%29/%2Cloose%3A/%5E%28%3F%3A%28%3F%21%5B%5E%3A%40%5D%2B%3A%5B%5E%3A%40%5C/%5D%2A%40%29%28%5B%5E%3A%5C/%3F%23.%5D%2B%29%3A%29%3F%28%3F%3A%5C/%5C/%29%3F%28%28%3F%3A%28%28%5B%5E%3A%40%5D%2A%29%28%3F%3A%3A%28%5B%5E%3A%40%5D%2A%29%29%3F%29%3F%40%29%3F%28%5B%5E%3A%5C/%3F%23%5D%2A%29%28%3F%3A%3A%28%5Cd%2A%29%29%3F%29%28%28%28%5C/%28%3F%3A%5B%5E%3F%23%5D%28%3F%21%5B%5E%3F%23%5C/%5D%2A%5C.%5B%5E%3F%23%5C/.%5D%2B%28%3F%3A%5B%3F%23%5D%7C%24%29%29%29%2A%5C/%3F%29%3F%28%5B%5E%3F%23%5C/%5D%2A%29%29%28%3F%3A%5C%3F%28%5B%5E%23%5D%2A%29%29%3F%28%3F%3A%23%28.%2A%29%29%3F%29/%7D%7D%3Bvar%20sources%3D%7B%27images%27%3A%7B%7D%2C%27media%27%3A%7B%7D%2C%27script%27%3A%7B%7D%2C%27object%27%3A%7B%7D%2C%27frame%27%3A%7B%7D%2C%27font%27%3A%7B%7D%2C%27style%27%3A%7B%7D%7D%3Bvar%20directives%3D%7B%27images%27%3A%27img-src%27%2C%27media%27%3A%27media-src%27%2C%27script%27%3A%27script-src%27%2C%27object%27%3A%27object-src%27%2C%27frame%27%3A%27frame-src%27%2C%27font%27%3A%27font-src%27%2C%27style%27%3A%27style-src%27%7D%3Bfunction%20capWord%28w%29%7Breturn%20w.charAt%280%29.toUpperCase%28%29%2Bw.slice%281%29%3B%7D%0Afunction%20objIsEmpty%28obj%29%7Bfor%28var%20prop%20in%20obj%29%7Bif%28obj.hasOwnProperty%28prop%29%29%0Areturn%20false%3B%7D%0Areturn%20true%3B%7D%0Afunction%20generatePolicyFromSources%28sourceList%29%7Bvar%20policy%3D%22allow%20%27self%27%3B%22%3Bfor%28type%20in%20sourceList%29%7Bif%28objIsEmpty%28sourceList%5Btype%5D%29%29%0Acontinue%3Bpolicy%2B%3D%22%20%22%2Bdirectives%5Btype%5D%2B%22%20%22%2B%0AObject.keys%28sourceList%5Btype%5D%29.join%28%22%20%22%29%2B%22%3B%22%3B%7D%0Areturn%20policy%3B%7D%0AObject.keys%3DObject.keys%7C%7Cfunction%28obj%29%7Bvar%20keys%3D%5B%5D%3Bfor%28var%20key%20in%20obj%29%7Bif%28obj.hasOwnProperty%28key%29%29%0Akeys.push%28key%29%3B%7D%0Areturn%20keys%3B%7D%0Afunction%20analyzeContent%28%29%7Bvar%20myHost%3DparseUri%28location.href%29.host%3Bvar%20images%3DgetElements%28%22img%22%29%3Bfor%28var%20i%3D0%3Bi%3Cimages.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28images%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.images%29%29%0Asources.images%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.images%29%29%0Asources.images%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20linkElems%3DgetElements%28%22link%22%29%3Bfor%28var%20i%3D0%3Bi%3ClinkElems.length%3Bi%2B%2B%29%7Bif%28linkElems%5Bi%5D.getAttribute%28%22rel%22%29%3D%3D%22shortcut%20icon%22%29%7Bvar%20uriParts%3DparseUri%28linkElems%5Bi%5D.href%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.images%29%29%0Asources.images%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.images%29%29%0Asources.images%5Bhost%5D%3Dnull%3B%7D%7D%7D%0Avar%20media%3DgetElements%28%22video%2Caudio%22%29%3Bfor%28var%20i%3D0%3Bi%3Cmedia.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28media%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.media%29%29%0Asources.media%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.media%29%29%0Asources.media%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20scripts%3DgetElements%28%22script%22%29%3Bfor%28var%20i%3D0%3Bi%3Cscripts.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28scripts%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.script%29%29%0Asources.script%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.script%29%29%0Asources.script%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20objAppl%3DgetElements%28%22object%2Capplet%22%29%3Bfor%28var%20i%3D0%3Bi%3CobjAppl.length%3Bi%2B%2B%29%7Bif%28objAppl%5Bi%5D.hasAttribute%28%22codebase%22%29%29%7Bvar%20uriParts%3DparseUri%28objAppl%5Bi%5D.getAttribute%28%22codebase%22%29%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%0Aif%28objAppl%5Bi%5D.hasAttribute%28%22classid%22%29%29%7Bvar%20uriParts%3DparseUri%28objAppl%5Bi%5D.getAttribute%28%22classid%22%29%29%3Bif%28%5B%22http%22%2C%22https%22%2C%22ftp%22%2Cnull%5D.indexOf%28uriParts%5B%22protocol%22%5D%29%21%3D-1%29%7Bvar%20host%3DuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%7D%0Aif%28objAppl%5Bi%5D.hasAttribute%28%22data%22%29%29%7Bvar%20uriParts%3DparseUri%28objAppl%5Bi%5D.getAttribute%28%22data%22%29%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%0Aif%28objAppl%5Bi%5D.hasAttribute%28%22archive%22%29%29%7Bvar%20uriParts%3DparseUri%28objAppl%5Bi%5D.getAttribute%28%22archive%22%29%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%7D%0Avar%20embeds%3DgetElements%28%22embed%22%29%3Bfor%28var%20i%3D0%3Bi%3Cembeds.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28embeds%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.object%29%29%0Asources.object%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20frameElems%3DgetElements%28%22frame%2Ciframe%22%29%3Bfor%28var%20i%3D0%3Bi%3CframeElems.length%3Bi%2B%2B%29%7Bvar%20uriParts%3DparseUri%28frameElems%5Bi%5D.src%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.frame%29%29%0Asources.frame%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.frame%29%29%0Asources.frame%5Bhost%5D%3Dnull%3B%7D%7D%0Avar%20stylesheets%3D%7B%7D%3Btry%7Bvar%20stylesheets%3Ddocument.styleSheets%3B%7D%0Acatch%28e%29%7B%7D%0Afor%28var%20i%3D0%3Bi%3Cstylesheets.length%3Bi%2B%2B%29%7Bvar%20rules%3D%7B%7D%3Btry%7Brules%3Dstylesheets%5Bi%5D.cssRules%3B%7D%0Acatch%28e%29%7Bcontinue%3B%7D%0Aif%28%21rules%29%7Bcontinue%3B%7D%0Afor%28var%20j%3D0%3Bj%3Crules.length%3Bj%2B%2B%29%7Bif%28rules%5Bj%5D.type%3D%3Drules%5Bj%5D.FONT_FACE_RULE%29%7Bvar%20src%3Drules%5Bj%5D.style.getPropertyValue%28%22src%22%29%3Bif%28src%29%7Bvar%20url%3Dsrc.replace%28/%5Eurl%5B%27%22%5D%2A/%2C%22%22%29.replace%28/%5B%27%22%5D%2A%5C%29%24/%2C%22%22%29%3Bvar%20uriParts%3DparseUri%28url%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.font%29%29%0Asources.font%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.font%29%29%0Asources.font%5Bhost%5D%3Dnull%3B%7D%7D%7D%7D%7D%0Avar%20linkElems%3DgetElements%28%22link%22%29%3Bfor%28var%20i%3D0%3Bi%3ClinkElems.length%3Bi%2B%2B%29%7Bif%28linkElems%5Bi%5D.getAttribute%28%22rel%22%29%3D%3D%22stylesheet%22%29%7Bvar%20uriParts%3DparseUri%28linkElems%5Bi%5D.href%29%3Bvar%20host%3D%28uriParts%5B%22protocol%22%5D%3D%3D%22data%22%29%3F%22data%3A%22%3AuriParts%5B%22host%22%5D%3Bif%28host%3D%3Dnull%29%7Bif%28%21%28host%20in%20sources.style%29%29%0Asources.style%5B%22%27self%27%22%5D%3Dnull%3B%7D%0Aelse%7Bif%28host%3D%3DmyHost%29%0Ahost%3D%22%27self%27%22%3Bif%28%21%28host%20in%20sources.style%29%29%0Asources.style%5Bhost%5D%3Dnull%3B%7D%7D%7D%0Aalert%28generatePolicyFromSources%28sources%29%29%3B%7D%0AanalyzeContent%28%29%3B" class="bookmarklet">Recommend CSP</a></p>
<p>If you find it useful, drag it to your <a href="http://support.mozilla.com/en-us/kb/bookmarks#Where_to_find_bookmarks">bookmarks toolbar</a> and you can use it from any web page.  Feel free to check out the <a href="https://github.com/bsterne/bsterne-tools/blob/master/csp-bookmarklet/csp-bookmarklet.js">bookmarklet source</a> as well.</p>
<p>In the future, I would like to add notifications for potential <a href="https://developer.mozilla.org/en/Security/CSP/Default_CSP_restrictions#Restricted_scripts">inline script violations</a>.</p>
<style type="text/css">
a.bookmarklet {
  text-decoration: none;
  display: inline-block;
  border: 1px solid #bbb;
  padding: .25em .5em;
  margin: .5em;
  -moz-border-radius: .5em;
  -webkit-border-radius: .5em;
}
</style>
]]></content:encoded>
			<wfw:commentRss>http://brandon.sternefamily.net/posts/2010/10/content-security-policy-recommendation-bookmarklet/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sharing Links</title>
		<link>http://brandon.sternefamily.net/posts/2010/05/sharing-links/</link>
		<comments>http://brandon.sternefamily.net/posts/2010/05/sharing-links/#comments</comments>
		<pubDate>Fri, 28 May 2010 16:23:50 +0000</pubDate>
		<dc:creator>bsterne</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://brandon.sternefamily.net/posts/?p=320</guid>
		<description><![CDATA[Sometimes I make a tool that I use for a while and then wonder if it&#8217;s something others will find useful too. Here&#8217;s one of them&#8230; For a while I was sharing links on my home page by linking to the feed of stories I&#8217;ve upvoted on Reddit, but that has become less satisfying as [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css">
a.bookmarklet {
  text-decoration: none;
  border: 1px solid #bbb;
  margin: 1em;
  padding: .5em;
  -moz-border-radius: .5em;
  -webkit-border-radius: .5em;
}
</style>
<p style="margin:0 2em"><em>Sometimes I make a tool that I use for a while and then wonder if it&#8217;s something others will find useful too.  Here&#8217;s one of them&#8230;</em></p>
<p>For a while I was sharing links on my home page by linking to the feed of stories I&#8217;ve <a href="http://www.reddit.com/user/jackthecoiner/liked/">upvoted on Reddit</a>, but that has become less satisfying as Reddit dumbs itself down each day (the same thing that happened to Digg a few years earlier).  I decided to make my own link-sharing program that I could use by just clicking a <a href="http://en.wikipedia.org/wiki/Bookmarklet">bookmarklet</a> whenever I was on a page I wanted to share.</p>
<p>It is a very simple program that stores the links in a flat text file and uses <a href="http://www.w3.org/TR/cors/#access-control-allow-origin-response-hea">CORS</a> to allow the bookmarklet to POST data to it from across domains.  You can put the files in a directory on your server and use this simple bookmarklet to share links:</p>
<p style="margin:1em; font-size:80%">Drag this to your bookmarks toolbar: <a href='javascript:var shareUrl = "http://your.server/share/index.php"; var pw = "p@ssword";  function createXHR() {   if (window.XMLHttpRequest) {     return new XMLHttpRequest();   }   else if (window.ActiveXObject) {     return new ActiveXObject("Microsoft.XMLHTTP");   }   else {     return null;   } }  function handleResponse() {   if (http.readyState == 4 &#038;&#038; http.status == 200) {     var response = http.responseText;     if (response.length)       alert(response);   } }  var text = prompt("Enter Link Text", document.title);  if (text != "" &#038;&#038; text != null) {   var url = window.location.href;   var params = "text=" + escape(text) + "&#038;url=" + escape(url) + "&#038;pw=" + pw;    var http = createXHR();   http.open("POST", shareUrl, true);   http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");   http.onreadystatechange = handleResponse;   http.send(params); }' class="bookmarklet">Share This</a></p>
<div class="middleBlock">
<p>You can check out the <a href="/files/share/index.txt">server code</a> or the <a href="/files/share/bookmarklet.js">bookmarklet source</a>, or you can download the <a href="/files/share.zip">zip archive</a> and extract the files on your server.</p>
</div>
<p>When you fetch the server script with GET you get back a <a href="/share/index.php?format=json">JSON</a> or <a href="/share/index.php?format=rss">RSS</a> feed depending on the <code>format</code> parameter you pass.</p>
<p>Make sure the password in the bookmarklet stays synced with the password in the server file and change them to something secure.</p>
]]></content:encoded>
			<wfw:commentRss>http://brandon.sternefamily.net/posts/2010/05/sharing-links/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RSS Feed Monitor &#8211; Update</title>
		<link>http://brandon.sternefamily.net/posts/2006/09/rss-feed-monitor-update/</link>
		<comments>http://brandon.sternefamily.net/posts/2006/09/rss-feed-monitor-update/#comments</comments>
		<pubDate>Sun, 24 Sep 2006 18:59:11 +0000</pubDate>
		<dc:creator>bsterne</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://brandon.sternefamily.net/posts/?p=54</guid>
		<description><![CDATA[I updated the RSS Feeds Monitor I wrote in Python last month to enable database logging as well as a debug mode which prints output to the console. Both the new code and the old code are available.]]></description>
			<content:encoded><![CDATA[<p>I updated the <a href="/posts/2006/08/rss-feed-monitor/">RSS Feeds Monitor</a> I wrote in Python last month to enable database logging as well as a debug mode which prints output to the console.  Both the <a href="/files/feedMonitor.txt" title="Python RSS Feed Monitor">new code</a> and the <a href="/files/feedMonitor_old.txt">old code</a> are available.</p>
]]></content:encoded>
			<wfw:commentRss>http://brandon.sternefamily.net/posts/2006/09/rss-feed-monitor-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Texas Hold &#8216;Em</title>
		<link>http://brandon.sternefamily.net/posts/2006/09/php-texas-hold-em/</link>
		<comments>http://brandon.sternefamily.net/posts/2006/09/php-texas-hold-em/#comments</comments>
		<pubDate>Mon, 18 Sep 2006 19:05:18 +0000</pubDate>
		<dc:creator>bsterne</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://brandon.sternefamily.net/posts/?p=57</guid>
		<description><![CDATA[I've been quite obsessed with poker lately.  Between the <a href="http://en.wikipedia.org/wiki/World_Series_of_Poker">WSOP</a> and the <a href="http://www.worldpokertour.com/">WPT</a>, it's not hard to pick up poker strategy from TV.  Along those lines, I decided to write a <a href="/posts/2006/9/php-texas-hold-em/" title="PHP Texas Hold Em Poker">web-based poker game</a>.  For now, the game deals hands of <a href="http://en.wikipedia.org/wiki/Texas_hold_'em">Hold 'Em</a> and picks out the best 5 card poker hand.  Eventually I'd like to expand the game to include computer players and allow multiple human players to play against each other online.  Feel free to <a href="/files/poker.txt">check out the source</a>.]]></description>
			<content:encoded><![CDATA[<style type="text/css">
td.blackcard{
  font-size:200%;
  text-align:center; 
  width:75px;
  height:105px;
  background-image:url(/posts/images/blank_card.gif);
  background-repeat:no-repeat;
  background-position:center center;
}
td.redcard{
  font-size:200%;
  text-align:center; 
  width:75px;
  height:105px;
  background-image:url(/posts/images/blank_card.gif);
  background-repeat:no-repeat;
  background-position:center center;
  color:red;
}  
</style>
<p><br/><br />
<b>Table cards:</b><br/><br />
<table>
<tr>
<td class="blackcard">8&clubs;</td>
<td class="blackcard">A&clubs;</td>
<td class="redcard">9&diams;</td>
<td class="redcard">A&diams;</td>
<td class="blackcard">8&spades;</td>
</tr>
</table>
<p><b>Your cards:</b><br/><br />
<table>
<tr>
<td class="blackcard">J&spades;</td>
<td class="blackcard">4&spades;</td>
</tr>
</table>
<p><br/><br />
<b>Result:</b> 2 Pair<br/><b>Hands required:</b> 1          <br/><br/><br />
          <b>Hand Type:</b><br/></p>
<form method="get">
<table>
<tr>
<td style="width:14%; text-align:center">Any</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="any"  checked="checked" /></td>
<td style="width:14%; text-align:center">Pair</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="pair"  /></td>
<td style="width:14%; text-align:center">2 Pair</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="2pair"  /></td>
<td style="width:14%; text-align:center">3 of a Kind</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="3ofakind"  /></td>
<td style="width:14%; text-align:center">Straight</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="straight"  /></td>
</tr>
<tr>
<td style="width:14%; text-align:center">Flush</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="flush"  /></td>
<td style="width:14%; text-align:center">Full House</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="fullhouse"  /></td>
<td style="width:14%; text-align:center">4 of a Kind</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="4ofakind"  /></td>
<td style="width:14%; text-align:center">Straight Flush</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="straightflush"  /></td>
<td style="width:14%; text-align:center">Royal Flush</td>
<td style="width:5%; text-align:center">
<input type="radio" name="hand" value="royalflush"  /></td>
</tr>
<tr>
<td colspan="10" style="text-align:center; padding:10px">
<input type="submit" value="Deal Hand" /></td>
</tr>
</table></form>
]]></content:encoded>
			<wfw:commentRss>http://brandon.sternefamily.net/posts/2006/09/php-texas-hold-em/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RSS Feed Monitor</title>
		<link>http://brandon.sternefamily.net/posts/2006/08/rss-feed-monitor/</link>
		<comments>http://brandon.sternefamily.net/posts/2006/08/rss-feed-monitor/#comments</comments>
		<pubDate>Wed, 23 Aug 2006 02:23:37 +0000</pubDate>
		<dc:creator>bsterne</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://brandon.sternefamily.net/posts/?p=51</guid>
		<description><![CDATA[I wrote a Python <a href="/files/feedMonitor.txt">script</a> that <a href="/posts/2006/08/rss-feed-monitor/">monitors RSS feeds</a> for specified keywords and then sends emails to notify you of new posts.]]></description>
			<content:encoded><![CDATA[<div class="middleBlock">
<p><b>24-Sep-2006: Update</b></p>
<p>I&#8217;ve added <a href="/files/feedMonitor.txt">code</a> that logs each alert to a local database so that 1) duplicate alerts aren&#8217;t sent, even if the the stories are posted days or weeks apart, and 2) you can easily check which alerts have been sent historically.</p>
<p>Feel free to download the <a href="/files/feedMonitor.txt">new code</a> or the <a href="/files/feedMonitor_old.txt">old code</a> and <a href="/contact.php">tell me what you think</a>.</p>
<p>Additionally I added a debug mode such that if you run</p>
<p><code>> ./feedMonitor.py --console</code></p>
<p>the script prints to the console only and doesn&#8217;t send the email or log to the DB, so that you can see what types of alerts might be sent with the present script options.</p>
<p>Lastly, a <a href="/files/alertlist.txt">simple PHP script</a> can be used to display the alerts which have been sent in a <a href="/files/alertlist.php">HTML table that looks like this</a>.</p>
</div>
<p>I recently wrote a <a href="/files/feedMonitor.txt">Python script which monitors RSS feeds</a> for user-specified keywords.  The need for this script arose from the large number of security websites and mailing lists I monitor for work-related posts.  And you know how big a fan of automation I am&#8230;</p>
<p>All you need to run this script is <a href="http://python.org">Python</a> and a <a href="http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol">SMTP</a> server to send messages.  If you know of an <a href="http://en.wikipedia.org/wiki/Open_relay">open SMTP relay</a> feel free to use that, but you may find it easier to simply install <a href="http://www.sendmail.org/">Sendmail</a> locally.  The script is configured by default to send messages to <code>localhost</code>, so if you&#8217;re going to go the open relay route, you&#8217;ll need to configure the script accordingly.</p>
<p>For now, it is probably best to set the script up to run as a <a href="http://en.wikipedia.org/wiki/Crontab">cron job</a> and have the script run automatically every 10-30 minutes or so, depending on how urgently you need the alerts to come.  Eventually, I will add to the script the ability to log which alerts were mailed in a SQL database so that 1) you don&#8217;t receive duplicate alerts, and 2) you can have a record of which alerts have been mailed historically.</p>
<p>Stay tuned for updates to the script, and feel free to <a href="/contact.php">contact me</a> if you have any questions.</p>
]]></content:encoded>
			<wfw:commentRss>http://brandon.sternefamily.net/posts/2006/08/rss-feed-monitor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My eBay Watch List</title>
		<link>http://brandon.sternefamily.net/posts/2006/04/my-ebay-watch-list/</link>
		<comments>http://brandon.sternefamily.net/posts/2006/04/my-ebay-watch-list/#comments</comments>
		<pubDate>Mon, 03 Apr 2006 02:05:47 +0000</pubDate>
		<dc:creator>bsterne</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://brandon.sternefamily.net/posts/?p=41</guid>
		<description><![CDATA[I made my first foray into the immense <a href="http://developer.ebay.com">eBay API</a>.  Using eBay's authentication token technology, I wrote a <a href="/files/eBayWatchList.txt">function</a> that allows web developers to print the items from a user's My eBay without using their site credentials.  Check out the <a href="/posts/2006/04/my-ebay-watch-list/">write-up</a>.]]></description>
			<content:encoded><![CDATA[<div class="middleBlock">
<p><b>01-Sep-2009: Update</b></p>
<p>This code no longer works with the current eBay API, but I&#8217;ll leave it posted for reference.</p>
</div>
<p><a href="http://www.ebay.com">eBay</a> has some very cool functionality that allows application programmers to make API calls on a user&#8217;s behalf without using their site credentials.  I decided to investigate the eBay API a bit and wrote a function that allows web developers to print the items listed in an eBay buyer&#8217;s <a href="http://my.ebay.com">My eBay</a> section on third party web pages.  Feel free to <a href="/files/eBayWatchList.txt">check out the code</a>.</p>
<p>The <a href="http://developer.ebay.com">eBay Developer Program</a> has a <a href="http://developer.ebay.com/quickstartguide">guide</a> to help developers begin using the API.  You can make all kinds of unauthenticated function calls to the API, like listing search results, without using eBay&#8217;s Auth and Auth (Authentication and Authorization) system.  But to make calls on behalf of a particular user, you will need to generate an auth token.  This can be done using eBay&#8217;s <a href="http://developer.ebay.com/tokentool/">Authentication Token Tool</a>.</p>
<p>Essentially, this process works by entering an eBay user&#8217;s site crentials in the token generator and eBay returns a cryptographic token.  This token can then be passed along with the API function calls to authenticate the caller without including the user&#8217;s login and password.</p>
<p>The function I wrote is essentially a wrapper to the API call <span style="font-family:monospace">GetMyeBayBuying</span>.  Calling my function, <span style="font-family:monospace">printMyEbay</span>, will print the auctions that a user is a) watching, b) bidding on, and c) has won.</p>
]]></content:encoded>
			<wfw:commentRss>http://brandon.sternefamily.net/posts/2006/04/my-ebay-watch-list/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

