<?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>jr conlin&#039;s ink stained banana</title>
	<atom:link href="http://blog.unitedheroes.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.unitedheroes.net</link>
	<description>it&#039;s teaching the monkey to stop typing that&#039;s hard...</description>
	<lastBuildDate>Mon, 07 May 2012 23:45:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Idiots Guide to Mozilla Sync API</title>
		<link>http://blog.unitedheroes.net/archives/p/4492/idiots-guide-to-mozilla-sync-api/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4492/idiots-guide-to-mozilla-sync-api/#comments</comments>
		<pubDate>Mon, 07 May 2012 19:09:48 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[geek]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4492</guid>
		<description><![CDATA[i've been informed that Sync is due for a change and that what you read here may not be outdated in a few months. (grumble.) Be forewarned. Recently, i needed a way to sync data for my Firefox add-on between clients. Fortunately, there's a nifty way to do that built into the current versions of [...]]]></description>
			<content:encoded><![CDATA[<div class="update">i've been informed that Sync is due for a change and that what you read here may not be outdated in a few months. (grumble.)<br />
Be forewarned.</div>
<p>Recently, i needed a way to sync data for my Firefox add-on between clients. Fortunately, there's a nifty way to do that built into the current versions of Firefox called <a href="http://support.mozilla.org/en-US/kb/what-firefox-sync" target="_blank">Sync</a>. Unfortunately, while <a href=/val"https://developer.mozilla.org/en/Firefox_Sync/JavaScript_Client_API">the documentation</a> is great if you want to learn how sync operates, it's kinda poop if you want to quickly get started using Sync.</p>
<p>Well, "Some see problems, others see opportunities" so as my first go to fix that problem, i'm going to write down how i got Sync working.<br />
<!-- more --></p>
<h2>The Guts</h2>
<p>Ok, before we start delving into code, let's take a moment to talk about what's going on. Sync is a tool that securely exchanges data between two clients. That means you can use it to exchange data between anything you own that can run Firefox. (There are a couple of other browsers out there that can also play along, but for simplicity, let's stick to just firefox for now). It does this by stuffing your data into a well known chunk (marshalling), encrypting it, and sending it via a well known server. </p>
<p>Note, that the server isn't doing much more than relaying your data. That's because it's encrypted and can't really do anything with it right now. (Mozilla is working on making a more "durable" storage tool, but it's not there yet. This is why Mozilla STRONGLY RECOMMENDS you don't think of Sync as a backup service. It is, kind of like the shelf at the ATM is somewhere you can put your wallet. It's useful while the main bit is used, but not a really good long term idea.</p>
<p>Ok, so we've got records that are being exchanged. Those records have a little bit of information associated with them that's useful for syncing, but otherwise they're very simple. Those records go into a "Storage" object that just collects and manages the records, are watched by a "Tracker", and the storage elements get exchanged by an "Engine" that does the actual exchange. The engine watches both for local changes and remote requests for updates. It's worth noting that the exchange isn't instant, but near enough for most usages (e.g. within a few seconds).</p>
<p>Got it? The Tracker notices a change, and asks the Storage element to update the associated Records, then calls the Engine to deliver them. </p>
<p>There, now you understand Sync.</p>
<h2>Spelunking</h2>
<p>Now that you get Sync (from a tool point of view, at least), i can point out where some of the code lives. You don't need to look at this, but it might be useful if you like to play along at home.<br />
First off, <a href="https://hg.mozilla.org/mozilla-central/file/448f554f6acb/services/" target="_blank">here's where the sync code lives</a>. Most of what you want is in the <span class="code">sync/modules</span> branch.</p>
<p>If you want to see the code i built, you can <a href="https://github.com/jrconlin/push-addon/blob/dev/lib/fncrypto.js" target="_blank">find the latest version here</a>.</p>
<h2>The ground up&#8230;</h2>
<p>The addon i'm modifying is built off of the <a href"https://addons.mozilla.org/en-US/developers/">Addons SDK</a>. The nice thing is that this means the addon is restartless, the bad thing is that it means i have to do some extra work in order to get things running. In this case, i need to call into Mozilla Core code. To do that, though, you just need to call:<br />
<code><br />
const {Cu} = require('chrome');  // get the Components.utils hook<br />
Cu.import('resource://services-sync/engines.js');<br />
Cu.import('resource://services-sync/record.js');<br />
Cu.import('resource://services-sync/main.js');<br />
Cu.import('resource://services-sync/util.js');<br />
</code><br />
This automagically drags a host of objects into the current namespace. Chances are, if you're wondering where an object is defined, it's within one of these files. </p>
<p>Now, let's work from the ground up, that means building a Record object. Like i said before, a Record is just a marshalling container. The only real restriction is that it should be JSON storable (so fancy JS pointer hacks or methods are not really a good idea). </p>
<p>So, something simple:<br />
<code>function FooRecord(moduleName, recordId) {<br />
    CryptoWrapper.call(this, moduleName, recordId);<br />
}<br />
FooRecord.protoType = {<br />
    __proto__: CryptoWrapper.prototype; // subclass from CryptoWrapper<br />
    _logName: "Record.FNCrypto;         // What to use for the log messages<br />
};<br />
Utils.deferGetSet(FooRecord, "cleartext", ["value"]);<br />
</code><br />
As you can see, this subclasses CryptoWrapper (via janky JS subclassing), and then calls a utility function to autobuild the Getter/Setter method, which will store FooRecord.value into "this.cleartext.value". Ok, you probably didn't see that. You'll have to take my word for it. Now, if you had a very complex item where you may not want to exchange every bit of info, you could define a bunch of items in that (where "value" is, and probably with a bit more descriptive labels). This way, you'd send just the bits you need so that things are pleasantly zippy. Since my records are small and not really something you'd want to split up anyway, i opted for a single value.</p>
<p>Now that we have a Record, we need something that can hold them. Let's define the <b>Store</b>. In many respects, this is another <a href="http://www.codinghorror.com/blog/2008/05/understanding-model-view-controller.html" target="_blank">Controller</a> layer, in that it calls to whatever you're using to actually store your data (the Model). In this case, think of DB as the model store. (<a href="https://addons.mozilla.org/en-US/developers/docs/sdk/1.0/packages/addon-kit/docs/simple-storage.html" target="_blank">DB</a> is the persistent storage that is available to Add-ons, and is pretty cool too.)</p>
<p><code><br />
function FooStore(moduleName) {<br />
    Store.call(this, moduleName);<br />
}<br />
FNSyncStore.prototype = {<br />
    __proto__: Store.prototype,<br />
    self: this,<br />
    itemExists: function(recordId) {<br />
        return DB[recordId] != undefined;<br />
    },<br />
    createRecord: function(recordId, moduleName) {<br />
        var record = new FNSyncRecord(moduleName, recordId);<br />
        if(DB[recordId]) {<br />
            /* Again, if we had multiple fields, make sure you set them here.<br />
             */<br />
            record.keyBundle = DB[recordId];<br />
            return record;<br />
        }<br />
        return undefined;<br />
    },<br />
    changeItemID: function(oldId, newId) {<br />
        DB[newId] = DB[oldId];<br />
        delete DB[oldId];<br />
    },<br />
    getAllIDs: function() {<br />
        /* It's important that this return an Object (a Dict/Hash)*/<br />
        var recordIds = {};<br />
        for (var key in DB) {<br />
            /* Only return keys that are actually pointing to values.<br />
             * DB is a JS object, so there can be all kinds of cruft in there.<br />
             */<br />
            if (key.indexOf('key:') === 0) {<br />
                /* The value stored is arbitrary. Only the key name is important.<br />
                 */<br />
                recordIds[key]=true;<br />
            }<br />
        }<br />
        return recordIds;<br />
    },<br />
    wipe: function() {<br />
        for (var i in self.getAllIDs()){<br />
            delete DB[i];<br />
        }<br />
    },<br />
    /* These are meta function calls to normalize data sets<br />
     * between this machine and some other.<br />
     */<br />
    create: function(record) {<br />
        DB[record.id] = record.payload;<br />
    },<br />
    update: function(record) {<br />
        DB[record.id] = record.payload;<br />
    },<br />
    remove: function(record) {<br />
        delete DB[record.id];<br />
    }<br />
}<br />
</code><br />
Again, very simple, but a few caveats in there. One thing that can be confusing is that "createRecord" is different than "create". Create Record is more of a "write" function, in that it's called when a record has changed and it needs to be written out to some other device. "Create" is the opposite, that's where a new record needs to be imported onto the local machine. That's pretty much the role of Store. </p>
<p>Ok, we've got the transfer record, we've got the Storage/controller stuff, now we need to look at the Tracker to spot local changes. That's the role of <b>Tracker</b>.<br />
<code>function FNSyncTracker(moduleName){<br />
    Tracker.call(this, moduleName);<br />
    trackerInstance = this;<br />
}<br />
FNSyncTracker.prototype = {<br />
        __proto__: Tracker.prototype,<br />
        track: function(recordId){<br />
            /* Add the record to the list of items that have changed.<br />
             */<br />
            this.addChangedID(recordId);<br />
            /* Any dirty records need to be propagated as soon as possible.<br />
             * thus the immediate "100"<br />
             */<br />
            this.score = 100;<br />
        }<br />
}<br />
</code><br />
Really. That's about it. Basically, once data has changed on your side, you indicate to the Tracker "Hey, this changed!". You'll also want to set the score for how important it is to sync this data (0 == ignore this, 100 == OMFG THIS NEEDS TO BE DONE LIKE AN HOUR AGO!). You can set observers to help do this, or just call directly. i took the second option because i know exactly when i need to update and it's kind of important to do it after new record creation.</p>
<p>And finally, we're at the top level, the <b>Engine</b>:<br />
<code><br />
function FooEngine() {<br />
        // Defining "moduleName" here so that it's easy to figure out where<br />
        // it comes from. This is case insensitive.<br />
        var moduleName = "Foo";<br />
        Weave.SyncEngine.call(this, moduleName);<br />
        // turn the engine on<br />
        this.enabled = true;<br />
}<br />
FNSyncEngine.prototype = {<br />
        __proto__: Weave.SyncEngine.prototype,<br />
        _storeObj: FooStore,<br />
        _recordObj: FooRecord,<br />
        _trackerObj: FooTracker,<br />
        version: 1<br />
};<br />
</code><br />
Hey, so that's where the Module name comes from! Module name is used for a number of things, including logging and tracking. Unfortunately, it doesn't show up on the list of active sync engines on the options panel, yet. It does mean that it has to be a fairly unique, yet human readable string, so "Foo" is probably sub-optimal. The other thing you'll need to do is make sure that the engine is enabled (this caught me hard). </p>
<p>You'll also need to define links to the objects you've built, and the version you're using. </p>
<h2>And, you're done!</h2>
<p>That's it. Granted, you'll want to test this, and debug it, and all the other nonsense, but from a code sense, that's all you'll really need. </p>
<p>By the way, since i mentioned debugging, i want to chime in on the built in tools for Aurora and Nightly. Sadly, there's still no step-debugger, but here's a stupid trick that is INCREDIBLY useful: </p>
<ol>
<li>go to about:config</li>
<li>Open a Web Console [Ctrl+Shift+K]</li>
</ol>
<p>You now have a web console that can run Javascript with the Browser Chrome. That means that you can run things like <span class="code">Components.util.import('resource://services-sync/utils.js'); Utils.sha1('foo');</span> and get a pretty SHA1 hash of foo on your screen. And yeah, you can do the same trick with any other Mozilla core function you want to play with.</p>
<p>So, now you know, and knowing is half the battle.<br />
The other half involves blue and red lasers and guys with stupid nicknames.</p>

[No Comments]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4492/idiots-guide-to-mozilla-sync-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The x500 DRINKing Game</title>
		<link>http://blog.unitedheroes.net/archives/p/4487/the-x500-drinking-game/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4487/the-x500-drinking-game/#comments</comments>
		<pubDate>Wed, 02 May 2012 20:47:29 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[cranky]]></category>
		<category><![CDATA[geek]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4487</guid>
		<description><![CDATA[In a previous life, i worked for a company that was building an x500 MTA. For those not in a fetal position beneath their desk at the very mention of that phrase, an MTA is a Mail Transfer Agent. It's what's responsible for getting your complaint about the new Timeline to zuck@facebook.com. x500 was the [...]]]></description>
			<content:encoded><![CDATA[<p>In a previous life, i worked for a company that was building an x500 MTA. For those not in a fetal position beneath their desk at the very mention of that phrase, an MTA is a Mail Transfer Agent. It's what's responsible for getting your complaint about the new Timeline to zuck@facebook.com. x500 was the "Improved" mail addressing format that didn't presume a user at a site, but instead qualified it by a list of things that described an individual, from least specific to most (e.g.<br />
<code>Country: US<br />
Province: California<br />
City: Mountain View<br />
Company: Widgetco<br />
Floor: 3<br />
FamilyName: Doe<br />
SurName: John<br />
DNAFingerprint: ATTACAG...<br />
</code><br />
etc.)</p>
<p>(i'll beg your forgiveness if the field names are not correct. The therapy helps blot that crap from my mind.)</p>
<p>What's important here is that x500 allows fairly arbitrary fields to be inserted into a given record. The MTA only has to pay attention to the ones that it recognizes, so you could build one that only responds to, say, "Company, FamilyName" if you're a place with a dozen, unrelated employees. The rest of the spec is all optional. This lead to all sorts of interesting <strike>ab</strike>uses, including one of the things i was working on that involved storing a cryptographic key inside of the record that tied back to the authorizing provider, allowing for a verification path to the central root authority, meaning that your headers were often far larger than the actual content of the message and that had to be magically stuffed through a 300baud modem in a timely manner.</p>
<p>Still, flexibility was a strong selling point for x500. So much so, that the example included the frivolous category of "FavoriteDrink", and provided a helpful collection of alcoholic concoctions for the various fictional individuals to imbibe. HaHa, what merriment shall be had!</p>
<p>Only, it was in a spec, so that <a href="http://www.ietf.org/rfc/rfc1274.txt" target="_blank">it became codified</a>. </p>
<p>Now, a few decades later, i fully expect that there are more than a few unit test cases for determining validity of records based on "drink", and some very confused intern wondering what the hell that field has to do with figuring out how <a href="http://www.isode.com/whitepapers/ic-6033.html" target="_blank">to partition</a> <a href="http://www.ossramblings.com/openldap_bind_zones_ldap2dns" target="_blank">their machines</a>. i have been that intern. It was not fun.</p>
<p>This is why i tend to be a little cautious when folks talk about "loose data definitions" in applications, unless they REALLY MEAN IT. As in, they define methods for how data can be stored, but do not require specific elements to be defined. The application is therefore required to determine if a record can be used or not. That tends to shoot a lot of holes into peoples designs, and i'm ok with that. You can't realistically expect anyone else to use something where you hand wave over something as important as "The Data You Use". </p>
<p>Well, unless you're also providing all the alcohol that they'll need to deal with that stuff.</p>

[No Comments]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4487/the-x500-drinking-game/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Communicate With All The Things</title>
		<link>http://blog.unitedheroes.net/archives/p/4483/communicate-with-all-the-things/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4483/communicate-with-all-the-things/#comments</comments>
		<pubDate>Thu, 26 Apr 2012 15:58:32 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[geek]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4483</guid>
		<description><![CDATA[Not too long ago, i heard a story about how a guy was making organs that tweet. As in building a heart that can provide monitoring and status information online. Granted, folks tend to vent their spleens when on the internet, but this could be a great deal more literal. Bad jokes aside, when i [...]]]></description>
			<content:encoded><![CDATA[<p>Not too long ago, i heard a story about how a guy was making <a href="http://www.cbc.ca/spark/2012/04/spark-179-april-22-25-2012/" target="_blank">organs that tweet</a>. As in building a heart that can provide monitoring and status information online. Granted, folks tend to vent their spleens when on the internet, but this could be a great deal more literal. </p>
<p>Bad jokes aside, when i heard the report, the first thing i thought of was "So, what happens when Twitter goes away?" </p>
<p>i get the concept at hand here, and what they are talking about. "Tweeting" means posting short messages. It's what folks understand. Like xeroxing a kleenex you hoovered up, still, there are a <a href="http://blog.makezine.com/2008/02/25/how-to-make-plants-talk-t/" target="_blank">growing</a> <a href="http://www.adafruit.com/blog/2009/03/26/tweet-a-watt-kits-now-available/" target="_blank">number</a> of services that provide that sort of messaging with little intent of being used by a wider audience. Why? Well, aside from the OAuth handshake, there's something innately appealing about the idea of being able to post info to a simple URL for yourself. </p>
<p>That's definitely the idea behind the "<a href="http://en.wikipedia.org/wiki/Internet_of_Things" target="_blank">Internet of Things</a>" you occasionally hear about. A web of devices talking to each other (and you). People are thinking about using sites like Twitter and Facebook as the channels of communication, but i'm not really comfy with the idea of those companies knowing my energy consumption patterns and glucose levels. Or, for that matter, <a href="www.youtube.com/watch?v=-zh9fibMaEk" target="_blank">my credit and insurance company</a> getting a hold of them without my approval.</p>
<p>So that's kind of the idea behind the stuff <a href="http://jbalogh.me/" target="_blank">Jeff</a> and i are working on, <a href="https://wiki.mozilla.org/Services/Notifications" target="_blank">Notifications</a>. In short, it's a simple way for sites (or devices) to post short messages to a URL and have them get to you. What's more, you have control over those messages, and can silence or drop a site easily. Devices also have it pretty easy and can either post stuff just to a URL, or pass them through an encryption filter that prevents the carrier from being able to read the contents. </p>
<p>Internally, i've been kinda selling Notifications as being "Twitter for Mozilla", but i'm not sure that's right. Really, it's "Send and forget" for stuff that needs to talk to other stuff. Even better, is that you can run your own server. Heck, you can even run your own client that blasts these messages to Facebook or Twitter as well. It's not tied to Firefox at all, and that's the beauty of it. </p>
<p>It's simple, secure, and under your complete control. i think that's kind of cool, and hopefully you will as well. </p>

[No Comments]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4483/communicate-with-all-the-things/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Talk to Your Parents About Privacy</title>
		<link>http://blog.unitedheroes.net/archives/p/4479/talk-to-your-parents-about-privacy/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4479/talk-to-your-parents-about-privacy/#comments</comments>
		<pubDate>Tue, 24 Apr 2012 04:09:13 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[geek]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4479</guid>
		<description><![CDATA[This evening Anne Marie got a call from a wireless phone from Boston. The gentleman on the other end of the line asked for "a Conlin", and started asking questions about the Conlin family. Anne Marie (clever girl) knew to hand me the phone. i greeted the gent and he asked if we had family [...]]]></description>
			<content:encoded><![CDATA[<p>This evening Anne Marie got a call from a wireless phone from Boston. The gentleman on the other end of the line asked for "a Conlin", and started asking questions about the Conlin family. Anne Marie (clever girl) knew to hand me the phone.</p>
<p>i greeted the gent and he asked if we had family from a certain city. i replied that i wasn't going to answer that question. He pressed and i replied "Sorry, but i don't give information like that over the phone."</p>
<p>"Why not?" he asked, somewhat concerned. "Who'd want to know?"</p>
<p>"Well, i could give you a few hundred reasons why i wouldn't give someone info about my family." i replied helpfully.</p>
<p>"Look, i'm a lawyer from Boston&#8230;"</p>
<p>"&#8230; and i'm a rocket scientist from Florida. i have no way to prove what you're saying as you have no way to prove what i'm saying." (Frankly, if this guy was a lawyer, he's a pretty bad one.)</p>
<p>"i'm just trying to find my sister&#8230;" and then he gave me a rather long winded story about himself, his sister and looking for family. i listened politely, informed him that i could offer no help, and then offered a few additional things that might help him out. </p>
<p>He yelled at me to calm down. i know i can speak quickly, but i was absolutely calm. Heck, i was in complete control of the situation and happy to assist in any manner that would not compromise myself or my family. There's lots of <a href="http://www.whitepages.com/name/Conlin/Michigan" target="_blank">Conlins in Michigan</a>, if he was estranged from his folks, chances are someone up there might have more history he could chase down. </p>
<p>Eventually he hung up, and i did a bit of research on my own. i couldn't find any lawyer in current practice or retired in Boston that matched his name. The cellphone number he provided is less than a year old (<a href="http://www.facebook.com/permalink.php?story_fbid=111751732196555&#038;id=109157542455974" target="_blank">some idiot posted it on Facebook</a> about a year ago) and there's scant information that matched any other part of his story. (e.g. high school or college records that match his or his "sister's" name for the approximate years they might have attended. Hell, <a href="http://en.wikipedia.org/wiki/Gunn_High_School" target="_blank">he even managed to miss on the name of the high school</a> he was supposed to have attended.) For what it's worth, i'm chalking it up as a scammer.</p>
<p>See, that's the thing about personal information. If my wife wasn't married to a paranoid info junkie like me, she'd probably happily give this guy all sorts of information about my family, that he could then use to <a href="http://www.nextstepsforfamilies.com/Fraud.html" target="_blank">commit all sorts of dastardly things</a>. </p>
<p>People's <a href="http://www.npr.org/blogs/money/2012/04/17/150815268/why-people-do-bad-things" target="_blank">first action is to try and help</a>. It's someone looking for family, meaning they might be a long lost great cousin. As the monkey said, "Why would anyone care who wasn't family?"</p>
<p>All that aside, even if he was legit, trying to find his sister by cold calling people in California might explain why the family would have nothing more to do with him.</p>

[1 Comment]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4479/talk-to-your-parents-about-privacy/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>#IPA Leaves a Bitter Taste</title>
		<link>http://blog.unitedheroes.net/archives/p/4470/bitter-feelings-toward-ipa/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4470/bitter-feelings-toward-ipa/#comments</comments>
		<pubDate>Wed, 18 Apr 2012 16:31:53 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[cranky]]></category>
		<category><![CDATA[geek]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4470</guid>
		<description><![CDATA[First off, i Am Not A Lawyer, nor do i play one on TV. i am about as qualified to speak with any form of intelligence on the subject of the legal concept of Intellectual Property as most lawyers are unable to grasp the concepts of software design. In short: 't ain't my thing. Setting [...]]]></description>
			<content:encoded><![CDATA[<p>First off, i Am Not A Lawyer, nor <a href="http://www.youtube.com/watch?v=ZYQ0WEdG54A" target="_blank">do i play one on TV</a>. i am about as qualified to speak with any form of intelligence on the subject of the legal concept of Intellectual Property as most lawyers are unable to grasp the concepts of software design. In short: 't ain't my thing. </p>
<p>Setting that aside, however, <a href="http://engineering.twitter.com/2012/04/introducing-innovators-patent-agreement.html" target="_blank">Twitter's recent announcement of the Innovators Patent Agreement</a> kinda leaves me feeling odd. In many respects, they're "Doing It Right&reg;". They're establishing a patent policy where folks creating the patents own the ideas, the patents can only be used defensively, the policy remains in effect even if the patents are later sold or transferred, and they're even <a href="https://github.com/twitter/innovators-patent-agreement/issues" target="_blank">hashing all this out on github.com</a>. Considering <a href="http://paulgraham.com/softwarepatents.html" target="_blank">the crapola state of software patents</a> and how they're stifling innovation, it's a good step toward solving <a href="http://www.guardian.co.uk/technology/2012/apr/18/oracle-google-court-smartphone" target="_blank">this sort of crap</a>.</p>
<p>But, then there's part of my brain that speaks up. You see, <a href="http://www.noreklaw.com/public_domain_vs_patents.htm" target="_blank">you can't patent things that are in the public domain</a>. In fact, you can modify, enhance or transform a concept, but the patent only applies to that modification (the same is true if you take an existing patent). Even then, your idea has to be a substantial improvement over the previous idea, and not just painting it blue or something. </p>
<p>So, why patent it at all?</p>
<p>Patents exist for one reason. To prevent you from doing something. If i can patent something, i can do whatever for the period of the patent, but if you want to do it, i have to let you. Most times, i'll let you if you pay me enough, but that's not always the case. Sometimes i won't grant you the right regardless of offers of compensation just out of spite. Right now, <a href="http://articles.businessinsider.com/2012-04-17/tech/31353778_1_android-phones-nexus-one-google-tv" target="_blank">companies are being bought and sold</a> just for their portfolio, which is immediately used against companies that are doing the same thing. It's an arms race. </p>
<p>If twitter, or an engineer were to release an idea into the public domain, it becomes prior art. That's why so many mobile devices have multi-touch (since <a href="http://dl.acm.org/citation.cfm?id=317461" target="_blank">the idea came out in 1985</a>). <a href="http://www.theregister.co.uk/2012/02/29/apple_multitouch_patent/" target="_blank">Apple owns some additional aspects of how that interface is used</a> within their UI, but that's about it. </p>
<p>i'm honestly curious about this. Part of this strikes me as painting flowers on warheads. These are still patents. They still exist to prevent you from doing things. If i wanted to create a library that uses concepts contained in these patents, that library is still subject to the holder enforcing those patents and either requesting my library to be removed or filing damages. That's what patents do. Yeah, i could make a very nice looking oven out of that crate of bullets, but <a href="http://mythbustersresults.com/episode85" target="_blank">i wouldn't want to make a pizza in it</a>. i'd still want to use ideas and methods that are in the public domain so i could avoid those issues. It's why <a href="http://en.wikipedia.org/wiki/Ogg" target="_blank">Ogg</a>, <a href="http://www.bzip.org/" target="_blank">bzip</a> and <a href="http://www.libpng.org/pub/png/pnghist.html" target="_blank">png</a> exist. </p>
<p>i'm just not sure what to make of this. It's a bit like declaring a <a href="http://en.wikipedia.org/wiki/Mutual_assured_destruction" target="_blank">Mutual Assured Destruction</a> policy after <a href="http://www.youtube.com/watch?v=c4TdPxOXuYw" target="_blank">Mad Max</a> has been driving around for a few decades. </p>
<p>If you want this stuff to be freely used, why not make it free?</p>
<div class="update"><a href="http://www.wac6.com/wac6/2012/04/patent-experts-deconstruct-twitters-employee-patent-assignment-ipa.html" target="_blank">Three patent attorneys look at the IPA in depth</a>, and ask some of the same questions. Good read to see what points they raise.</p>
<p>As i noted to @municode, i'm not against the #IPA, i'm just skeptical. Patents have trained me to look deeper than just what someone says.</p>
<p>Update2: <a href="http://www.wired.com/epicenter/2012/04/opinion-baio-twitter-patents/" target="_blank">Andy Baio writes his opinion of the #IPA</a>. Also an illuminating read. </div>

[7 Comments]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4470/bitter-feelings-toward-ipa/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>When Blackholes Merge</title>
		<link>http://blog.unitedheroes.net/archives/p/4454/when-blackholes-merge/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4454/when-blackholes-merge/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 03:52:44 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[cranky]]></category>
		<category><![CDATA[geek]]></category>
		<category><![CDATA[humor]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4454</guid>
		<description><![CDATA[Facebook has bought Instagram for $1,000,000,000. That's a lot of zeroes. Good Mr. Malik has a report that the reason Facebook wanted to buy Instagram was because they were both picture platforms. Yeah, that surprised me too. You see, when i think of a "picture platform" i think of sites like Flickr. Go to flickr.com [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://dealbook.nytimes.com/2012/04/09/facebook-buys-instagram-for-1-billion/" target="_blank">Facebook has bought Instagram for $1,000,000,000</a>. That's a lot of zeroes. <a href="http://gigaom.com/2012/04/09/here-is-why-did-facebook-bought-instagram/" target="_blank">Good Mr. Malik</a> has a report that the reason Facebook wanted to buy Instagram was because they were both picture platforms.</p>
<p>Yeah, that surprised me too.</p>
<p>You see, when i think of a "picture platform" i think of sites like Flickr. Go to <a href="http://www.flickr.com/" target="_blank">flickr.com</a> and feel free to waste an hour just looking at pictures. There are billions. Heck, there's even a page that shows photos that the community feels <a href="http://www.flickr.com/explore/interesting/7days/" target="_blank">are interesting</a>. What's more, you don't even have to have an account. That's really important. It means that anyone can view your photos because you're sharing them with the world.</p>
<p>That's kinda what photo sharing means to me.</p>
<p>Now, feel free to go to sites like <a href="http://instagram.com/" target="_blank">instagram.com</a> and do the same thing. Oh, wait, you can't. You have to download their app, create an account and find people who take good photos before you can see them. Well, at least there's facebook, right? Let me do a search for photos on facebook and&#8230; <a href="http://www.facebook.com/directory/pages/" target="_blank">oh</a>. Pretty much the same thing. i mean, i can do a search on <a href="https://www.google.com/search?q=site:facebook.com&#038;hl=en&#038;prmd=imvns&#038;source=lnms&#038;tbm=isch&#038;ei=hKyDT9nnFKuPigLsn5jCBQ&#038;sa=X&#038;oi=mode_link&#038;ct=mode&#038;cd=2&#038;ved=0CAsQ_AUoAQ&#038;biw=1131&#038;bih=984" target="_blank">google for facebook images</a>, i suppose, but that's not really useful. Even if i were publish a portfolio of photos that were free to use, you wouldn't be able to find them unless you knew i shared them and had a Facebook account.</p>
<p>See, this is where i say that both of these services are blackholes. They suck information in, but you're not really expected to get anything back out. Indeed, one could think of these services a bit like religions (albeit, not the better portions thereof):</p>
<ul>
<li>You can't do anything unless you're a member.</li>
<li>Members are always trying to convert the "unfaithful".</li>
<li>There are aspects that are accepted without proof. </li>
<li>One community may use them in a way that is quite different than another. </li>
<li>Changes are met with cries of "Heresy"!</li>
</ul>
<p>These are walled gardens and you're not allowed in unless you genuflect. For all i know, both of these companies are making up numbers and statistics because there's no way for you to know otherwise.</p>
<p>You know what? Sure thing. i've also got an amazing platform with zillions of photos loaded up! Why here's frequent visitor Max Foucault (who is absolutely not a name i made from <a href="http://en.wikiquote.org/wiki/Mighty_Max" target="_blank">hitting</a> <a href="http://en.wikiquote.org/wiki/Anti-psychiatry" target="_blank">random</a> twice on wikiquotes) talking about how wonderful the service is:</p>
<blockquote class="letter"><p>[It's] fantastic! Couldn't live without it. In fact i wouldn't exist if it didn't!</p></blockquote>
<p>And look here's a photo from him that is in no way two images i grabbed off of pinterest and applied random filters to: <img src="http://blog.unitedheroes.net/wp-content/uploads/2012/04/max_p.png" alt="" title="max_p" width="192" height="256" align="right" class="alignnone size-full wp-image-4461" /></p>
<p>Don't believe me? That's because you're not part of the exclusive set of pre-alpha invitees and my crack team of imaginary developers, and there's no way for you to prove otherwise. </p>
<p>What's more, i'll even take .01% of what was offered for Instagram, because i believe <strike>in taking complete advantage of suckers</strike> that the service is such a benefit to humanity.</p>
<p>Isn't that right, noted Chinese Blogger Xū Rén:</p>
<blockquote class="letter"><p>Yes! Your service is the only one i use in China with all my Chinese friends who are Chinese!</p></blockquote>
<p>Odd that he didn't write that out.</p>

[No Comments]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4454/when-blackholes-merge/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iRabies</title>
		<link>http://blog.unitedheroes.net/archives/p/4456/irabies/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4456/irabies/#comments</comments>
		<pubDate>Sun, 08 Apr 2012 20:17:58 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[cranky]]></category>
		<category><![CDATA[humor]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4456</guid>
		<description><![CDATA[There you go, Mr. Conlin, you're all set with your new Smartphone. Thanks, and&#8230;[CLANK!] there you go, you're all set now too. Uh, Mr. Conlin, what is that? That? Oh, well, i want to make sure that your company is around a long time. That means your money should be safe, so that's my free [...]]]></description>
			<content:encoded><![CDATA[<style>q1{display:block;margin-left: 1em;} q2{display:block;margin-left: 4em;}</style>
<p><q1>There you go, Mr. Conlin, you're all set with your new Smartphone.</q1></p>
<p><q2>Thanks, and&#8230;<em>[CLANK!]</em> there you go, you're all set now too.</q2></p>
<p><q1>Uh, Mr. Conlin, what is that?</q1></p>
<p><q2>That? Oh, well, i want to make sure that your company is around a long time. That means your money should be safe, so that's my free security system for your cash register.</q2></p>
<p><em><strong>[SCREEEEEEEEEEECH!]</strong></em></p>
<p><q1>That&#8230; is a monkey.</q1></p>
<p><q2>Well, yes. Officially it's a Atelinae Ateles, or a "spider monkey". They're a new world monkey with very long limbs and a prehensile tail that&#8230;</q2></p>
<p><q1>&#8230; yes, but why is he attached to our cash register?</q1></p>
<p><q2>Because he's your new, free security system, duh! No worries about that monkey getting stolen, that leash is made out of woven titanium. Granted, he's a little "bitey" so i had to go for that to keep him from chewing through it too&#8230;</q2></p>
<p><em><strong>[SCREEEEEEECH!]</strong></em></p>
<p><q1>Mr. Conlin, i appreciate your offer but,&#8230;</q1></p>
<p><q2>Offer? No, quite the contrary! This bitey, angry monkey is my gift to you! It's free! And make sure you feed him and keep him up on his shots otherwise the ASPCA will probably not like you. Come to think of it, they may not like you having a monkey chained to your cash register either.</q2></p>
<p><q1>Mr. Conlin! We can't have that thing here! We can't get to the registers!</q1></p>
<p><q2>Well, then they're secure then aren't they? Besides, you'll love it! Kids love the cute little hat he's wearing. Was wearing. Is filling up with his poop.</q2></p>
<p><q1>Get that damn monkey out of my store right now!</q1></p>
<p><q2>Sure thing, after you tell me how i can get these apps off my phone.</q2></p>
<p><q1>Apps?</q1></p>
<p><q2>Yeah, like this Verizon Maps, NFL Football and Netflix. i appreciate the offer, but i don't use any of them and they keep demanding that i update them or use them. i can't remove them or disable them, so they're a bit like Cuddles, there.</q2></p>
<p><em><strong>[SCREEEEEEEEEEEEEECH!]</strong></em></p>
<p><q2>Sorry Cuddles, Daddy doesn't love you anymore. Maybe Uncle&#8230; Steve right? Steve, will love you. Make sure you wear protective gear if you hug him. Cuddles is strong and goes right for the jugular.</q2></p>
<p><q1>You can't bolt an angry monkey to our cash registers! </q1></p>
<p><q2>You're just jealous that you didn't think of it first. Now, about removing these apps&#8230;</q2></p>
<p><q1>Well, what about this MotoActive app? We didn't force that one on you.</q1></p>
<p><q2>True. Motorola also had concerns about their new Howler Monkey music gift i dropped off on their campus, but i'm sure they'll grow to love it.</q2></p>

[No Comments]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4456/irabies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tech, Not Toys</title>
		<link>http://blog.unitedheroes.net/archives/p/4450/tech-not-toys/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4450/tech-not-toys/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 17:22:55 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[cranky]]></category>
		<category><![CDATA[geek]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4450</guid>
		<description><![CDATA[My well meaning Mother-in-law clipped a story out of her local paper and mailed it to me. It was a local story about how some local schools are giving their students iPads to foster a "technology boost". i'm doing my best not to start swearing like a sailor right now. This is like trying to [...]]]></description>
			<content:encoded><![CDATA[<p>My well meaning Mother-in-law clipped a story out of her local paper and mailed it to me. It was a local story about how <a href="http://www.registercitizen.com/articles/2012/03/09/news/doc4f5987dba5841647256527.txt" target="_blank">some local schools are giving their students iPads to foster a "technology boost"</a>.</p>
<p>i'm doing my best not to start swearing like a sailor right now.</p>
<p>This is like trying to teach kids how to repair cars by getting them snap-tite models. </p>
<p>Yes, the iPad is nifty and intuitive and makes the web more portable than it's been in a while. There are professionals that have started using them as a replacement for laptops for taking notes, doing presentations and writing documents. While very expensive, some colleges have moved their texts to eBooks meaning that students don't have to worry about forgetting their tomes.</p>
<p>But as an actual tool for learning technology, it's a piece of crap. There's no native editor that lets you build web pages. There's no way to examine and alter source of a live page. There's no local compiler so you can build and play with programming. You lose half your screen real-estate to the friggin "keyboard".</p>
<p>Tossing iPads at kids and hoping that they learn something more than ballistic trajectory patterns of cartoon fowl just points out how clueless you are about how to use technology.</p>
<p>You want to give your kids an edge in technology? Let them break stuff. Give them tools that let them see computers aren't magical sealed boxes they're not to play with, but bundles of commands and handles that will do their bidding provided you ask them correctly. Point them at <a href="http://www.hackasaurus.org/" target="_blank">Hackasaurus.org</a> and let them dismantle and web page and learn javascript. Teach them python and Java. Give them Virtual Machines they can play with. Show them data stores like Cassandra and MySQL and let them see how they're both great and crap depending on how you use them.</p>
<p>Want your kids to be tech smart? Get them hacking. Get them excited about technology. Let them teach other kids so that the lessons really sink in. </p>
<p>Anything else, and you're basically buying your kids slot car racers and hoping that they'll win the Indy 500. </p>

[3 Comments]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4450/tech-not-toys/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Write It Down</title>
		<link>http://blog.unitedheroes.net/archives/p/4446/write-it-down/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4446/write-it-down/#comments</comments>
		<pubDate>Fri, 16 Mar 2012 02:46:44 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[crap]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4446</guid>
		<description><![CDATA[Sorry about the radio silence, regretfully, my father passed away recently. Like far too many of these sorts of things, it was both sudden and expected, and while i appreciate your kind thoughts and words, can i ask you to do something instead? My family doesn't have a great deal of recorded history. This is [...]]]></description>
			<content:encoded><![CDATA[<p>Sorry about the radio silence, regretfully, my father passed away recently.</p>
<p>Like far too many of these sorts of things, it was both sudden and expected, and while i appreciate your kind thoughts and words, can i ask you to do something instead?</p>
<p>My family doesn't have a great deal of recorded history. This is a bit of an annoyance being a fan of history (heh, something i inherited from my father). While we have great stories as a family, a good deal of it is lost to the ages. Since he got sick, i'd been pushing my Dad to write down some of the stories he remembered growing up. Granted, he was a humble man, and would argue that nobody would ever care about that stuff.</p>
<p>And we wonder why we didn't have a lot of family history.</p>
<p>Please don't make that mistake. Start a journal. It doesn't matter if you're not Hemmingway or all you ever eat for lunch is peanut butter and jelly. If you never had an exceptional moment in your life, that's exceptional and should be recorded somewhere. Write it down. People will want to read it. If not your family, then the fine folks at the Library of Congress and National Archives will happily take a copy and some future scholar may use it in his thesis. Or possibly they actually will make that movie about you. </p>
<p>Once your gone, so are your memories, unless you make the effort to tell them to someone. </p>
<p>Take the effort. </p>

[No Comments]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4446/write-it-down/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Could Someone Check My Math?</title>
		<link>http://blog.unitedheroes.net/archives/p/4429/could-someone-check-my-math/</link>
		<comments>http://blog.unitedheroes.net/archives/p/4429/could-someone-check-my-math/#comments</comments>
		<pubDate>Thu, 23 Feb 2012 21:38:19 +0000</pubDate>
		<dc:creator>jrconlin</dc:creator>
				<category><![CDATA[geek]]></category>

		<guid isPermaLink="false">http://blog.unitedheroes.net/?p=4429</guid>
		<description><![CDATA[Dear Lazyweb, i am not a math whiz. i get math, but not to the level that it's effortless music. So i'd appreciate ye far smarter folk double checking my thinking here. The Problem For the Notifications stuff i'm working on, i need a token that is Really Hard to Guess. That means Lots of [...]]]></description>
			<content:encoded><![CDATA[<p>Dear Lazyweb, </p>
<p>i am not a math whiz. i get math, but not to the level that it's effortless music. So i'd appreciate ye far smarter folk double checking my thinking here.</p>
<p><b>The Problem</b><br />
For the <a href="http://blog.unitedheroes.net/archives/p/4382/notifications-and-bipostal/" target="_blank">Notifications</a> stuff i'm working on, i need a token that is Really Hard to Guess. That means Lots of Entropy stuffed into a token.</p>
<p>Because this is going through SMTP, i have <a href="http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1" target="_blank">a hard limit of 64 characters</a>. While also not part of the RFC (or anything else, experience with various <acronym title="Mail Transfer Agents, like Gmail, AOL, etc.">MTA</acronym>s have shown that you're limited to a through z and 0 through 9. Using a handy <a href="http://www.redkestrel.co.uk/Articles/RandomPasswordStrength.html" target="_blank">Entropy Bit Calculator</a>, that shows that:</p>
<p>log<sub>2</sub>(36)*64 ~= 331 Bits of Entropy. </p>
<p>That means you have a 1 in 2<sup>331</sup> (or 4,374,501,449,566,023,848,745,004,454,235,242,730,706,338,861,700,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000) chance of guessing it. (In case you're curious, that's 4 duotrigintillion)</p>
<p>That's great, and all, but does lead one to wind up getting a token that is 64 characters of random crap, like:<br />
wgmrbj3d9pcv1op6opprw7hvjgzimzonakq3m02egtjh8zs2bzyuxnowfx5e9fxu</p>
<p>So i was asked to research how good/bad an idea it might be to make the token a little less random.</p>
<p><b>The Solution</b></p>
<p>Specifically, i was asked if i could create a token based on words. That means you'd get a token like:<br />
faucet.variorum.hambling.baiters.harmed.stoa.haysel.glandular.61<br />
i arbitrarily decided to separate the words with periods and back-fill with numbers.</p>
<p>That leads to some interesting math. </p>
<p>i pulled the <a href="http://dreamsteep.com/projects/the-english-open-word-list.html" target="_blank">English Open Word List</a> and collected all the words into a single file (dropping the words that have non-ascii characters). That produced a catalog of 128,766 candidate words. A crappy token generator script later, i found that the mean token consisted of 8 words and was about 61 characters long. By my guess, each token would consist of<br />
 [a-z]{2} +    // shortest word length was 2 characters<br />
 [a-z\.]{59} + // the bulk of the token would be character or a period<br />
 [a-z0-9\.]{3} // the remainder would be character, number or period</p>
<p>This would lead me to think that the base entropy would be something like:<br />
 (log<sub>2</sub>(26)*2) + (log<sub>2</sub>(27)*59) + (log<sub>2</sub>(37)*3)<br />
or about 306 bits of entropy. (1 in 130 novemvigintrillion odds)</p>
<p><b>The real problem</b></p>
<p>But i'm not sure that's true. </p>
<p>That's supposing that the core of the characters being used are taken randomly from that pool of 27 available characters. They're not. These are using words in the English language which means that <a href="http://www.cs.trincoll.edu/~crypto/resources/LetFreq.html" target="_blank">there are certain character distributions</a> which diminish the pool of potential entropy. Granted, that's masked somewhat by the varying word lengths, but that still means that there aren't a hell of a lot of words that have J, Q, X or Z in them, and that the <a href="http://www.urbandictionary.com/define.php?term=RSTLNE" target="_blank">default letter set that Wheel of Fortune picks for you</a> sucks.</p>
<p>If one takes only the letters that have a greater than 10% chance in 1000 of appearing, then you wind up with about 15 meaning you've got:</p>
<p>log<sub>2</sub>(26)*2 + log<sub>2</sub>(27)*59 + log<sub>2</sub>(37)*3 = 30 bits of entropy, or 1 in 1,073,741,824</p>
<p>That number is no where near good enough. It's even pronounceable. </p>
<p>So, really, the question comes down to: "How much entropy am i losing by using real words?"</p>
<p>Thanks, Lazyweb!</p>
<p>i'll just keep refreshing the page until you answer.</p>
<div class="update">As pointed out in the comments, the short answer is "It's a bad idea". You wind up picking 8 items out of a ~ 128K pool and that's not enough to prevent folks from reasonably guessing.</p>
<p>'tis good to have friends with big brains.</p></div>

[5 Comments]]]></content:encoded>
			<wfw:commentRss>http://blog.unitedheroes.net/archives/p/4429/could-someone-check-my-math/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.258 seconds -->
<!-- Cached page served by WP-Cache -->

