Delbridge.Org
tag:blog.delbridge.org,2012:/
Occasionally, I stumble onto something that hasn't been discussed elsewhere on the 'Net. It's rare, but when it happens, I share it here. Sometimes.
Mango 1.6
A Musician's Guide to Creative Commons, Part 2
urn:uuid:FACE69F4-7E98-2630-C10FE39615DBE86A
2011-06-01T08:06:00Z
2011-06-09T10:06:00Z
<p><img style="float: right;" src="/assets/content/images/cc_logo.gif" alt="Creative Commons Logo" width="200" height="200" />In <a href="/post.cfm/a-musician-s-guide-to-creative-commons" target="_blank">Part 1</a>
of this tutorial, I introduced you to Creative Commons, a convenient,
no-cost alternative to traditional copyright, but stopped short of
implementation and the inherent technobabble. Here, we'll discuss the
first of two steps recommended by the organization for proper
implementation of Creative Commons: <em>file tagging</em>.</p>
Dave Delbridge
<p><img style="float: right;" src="/assets/content/images/cc_logo.gif" alt="Creative Commons Logo" width="200" height="200" />In <a href="/post.cfm/a-musician-s-guide-to-creative-commons" target="_blank">Part 1</a> of this tutorial, I introduced you to Creative Commons, a convenient, no-cost alternative to traditional copyright, but stopped short of implementation and the inherent technobabble. Here, we'll discuss the first of two steps recommended by the organization for proper implementation of Creative Commons: <em>file tagging</em>.</p>
<h3>Introduction to MP3 Audio Tag FRAMES<br /></h3>
<p>Hidden within each MP3 audio file, there exists a bubble of information, a data <em>"tag"</em> containing dozens of descriptive fields, or <em>"metadata,"</em> called <em>"tag frames,"</em> for such common descriptors as <em>"Song
Title,"</em> <em>"Artist,"</em> and <em>"Musical Genre."</em> You'll see the values for these displayed in your favorite music software or portable music
player. And with the help of freely-available software applications, these tag frames are easy to add, update and remove from an MP3 audio file.</p>
<p>You might be surprised to learn that the official MP3 audio file format offers no native mechanism for embedding metadata. Instead, a de facto standard emerged from necessity <em>(and hackers)</em>, called <em>"ID3."</em> Its first version, ID3v1, offers fewer than a dozen of the most obvious audio descriptors and no mention of copyright. <a href="http://www.id3.org/id3v2.3.0" target="_blank">ID3v2</a>, on the other hand, introduced more than 80 <a href="http://www.id3.org/id3v2.3.0#head-e4b3c63f836c3eb26a39be082065c21fba4e0acc" target="_blank">pre-defined frame types</a>, including those for copyright and extended copyright information. As such, when discussing MP3 tagging for the purposes of copyright identification, we must limit our focus to ID3v2 and later versions.</p>
<p>For clarity, pictured below is a diagram of a fictitious MP3 audio file, for a fictitious song recorded by a fictitious band. <em>[You know the drill. "Any similarities to persons living or dead... yada, yada."]</em></p>
<p><em></em><img style="margin-top: 20px; margin-bottom: 20px; border: 0;" src="/assets/content/images/mp3_frames.gif" alt="MP3 Tag Frame Diagram" width="500" height="634" /></p>
<h3>ID3 Copyright Tag Frames</h3>
<p>To tag your MP3 audio files for Creative Commons copyright, you'll target three specific ID3 tag frames. These are:</p>
<ol>
<li>TCOP (Copyright statement) <em>(e.g., "2011, Resort Records Inc. Some
Rights Reserved. Licensed to the public under
http://creativecommons.org/licenses/by-nc/3.0/us/. Verify at
http://rigel7.com/track/everything/download/.")</em></li>
<li>WCOP (Internet URL of Copyright / Legal information page) <em>(e.g., "http://creativecommons.org/licenses/by-nc/3.0/us/")</em></li>
<li>WOAF (Internet URL of official file download page) <em>(e.g., "http://rigel7.com/track/everything/download/")</em></li>
</ol>
<p>Unfortunately, your tag editor <em>(discussed next)</em> might not follow standard ID3 tag
nomenclature. If there's no <em>"TCOP"</em> tag displayed, look for <em>"Copyright"</em>
or <em>"Copyright statement,"</em> for example. What's more, some tag editors
hide these and other, less popular, tags to conserve limited screen real estate. You'll need to locate and
enable an <em>"extended tags"</em> option and/or add the missing tags to the
application's customizable tag display. If no such option exists, you'll need to find a more robust MP3 tag editor.</p>
<h3>Tag Editors<br /></h3>
<p>Creative Commons offers a free software tool, <a href="http://wiki.creativecommons.org/CcPublisher" target="_blank">CC Publisher</a>, for tagging MP3 audio files from a convenient, purpose-built interface.
Unfortunately, I found the Windows version of this program to be prohibitively buggy. For example, it stripped the album artwork from my audio files.
Furthermore, the app is no longer under development and might never be fixed. Versions for MacOS and Linux are also offered and may or may not provide better performance. If you have experience with these, please share in the comments, below.</p>
<p><a title="ccPublisher Screen Capture" href="http://wiki.creativecommons.org/CcPublisher" target="_blank"><img style="vertical-align: middle; margin-top: 20px; margin-bottom: 20px; border: 0;" src="/assets/content/images/ccPublisher.gif" alt="ccPublisher Screen Capture" width="496" height="452" /></a></p>
<p>As Creative Commons gains popularity, expect to find MP3 encoders and MP3 export options native to your professional audio editing software that will duplicate the conveniences suggested by CC Publisher. Given sufficient demand, there might also arise freeware and shareware applications or online services built specifically for this purpose. As of this writing, I am aware of none.</p>
<p><a title="Mp3tag Screen Capture" href="/assets/content/images/mp3tag.gif" target="_blank"><img style="vertical-align: middle; margin-top: 20px; margin-bottom: 20px; border: 0;" src="/assets/content/images/mp3tag.gif" alt="Mp3tag Screen Capture" width="500" /></a></p>
<p>Finally, as a last resort, you can tag your MP3 audio files by hand, using any of the popular MP3 tag editors, like the free <a href="http://www.mp3tag.de/en/">Mp3tag</a> for Windows, by Florian Heidenreich. A Google search for "free MP3 tag editors" will turn up dozens of candidates. Unfortunately, without the guidance of a purpose-built app, this procedure is prone to human error. Proceed with caution. Check your work twice. Here we go....</p>
<h3>Manual Tagging, Step-by-Step</h3>
<p>Once your MP3 tag editor is installed, follow these steps:</p>
<ol>
<li>With your Internet web browser, <a href="http://creativecommons.org/choose/">select a license</a> from Creative Commons by completing their questionnaire.</li>
<li>Select the link: "See how your license will look."</li>
<li>Copy the license URL displayed in your browser's address bar. It should look similar to one of these:
<ul>
<li>http://creativecommons.org/licenses/by/3.0/us/</li>
<li>http://creativecommons.org/licenses/by-sa/3.0/us/</li>
<li>http://creativecommons.org/licenses/by-nd/3.0/us/</li>
<li>http://creativecommons.org/licenses/by-nc/3.0/us/</li>
<li>http://creativecommons.org/licenses/by-nc-sa/3.0/us/</li>
<li>http://creativecommons.org/licenses/by-nc-nd/3.0/us/</li>
</ul>
</li>
<li>Modify the following copyright statement with your own info, where <em>
"2011"</em> represents the audio file's year of publication; <em>"MyBand"</em>
represents the audio file's owner;
<em>"http://creativecommons.org/licenses/by-nc-nd/3.0/us/"</em> represents the
license URL (selected in step #3); and <em>
"http://www.mywebsite.com/downloads/mysong/"</em> represents the file's official
download page on the owner's (presumably, your band's) web site:
<ul>
<li>2011, MyBand. Some Rights Reserved. Licensed to the public under
http://creativecommons.org/licenses/by-nc-nd/3.0/us/. Verify at
http://www.mywebsite.com/downloads/mysong/.</li>
</ul>
</li>
<li>In your MP3 tag editor, copy the completed copyright statement from
Step #4 and paste into the Copyright tag frame of your MP3 file. Again, this is technically called the "TCOP" tag frame.</li>
<li>In your MP3 tag editor, copy the license URL from Step #3 and paste
into the Copyright URL tag frame of your MP3 file. Again, this is technically called
the "WCOP" tag frame.</li>
<li>In your MP3 tag editor, paste the file's official download page URL
into the File URL tag frame of your MP3 file. This is the
"WOAF" tag frame. We will discuss the content of your official download page in Part 3 of this article. For now, you need only know the web page address where this information will be permanently published.</li>
</ol>
<h3>AUTOMATED, COMMAND-LINE TAGGING</h3>
<p>Now that you understand the individual steps, there's no reason to repeat them for every MP3 audio file you produce. With command-line tools, we can apply routine tagging robotically and even to multiple files in one shot.</p>
<p>Perhaps the best and most popular command-line MP3 encoder on the planet is the <a href="http://lame.sourceforge.net/" target="_blank">LAME Project</a>'s LAME MP3 encoder. An open development community, LAME skirts MP3's licensing requirements by offering only uncompiled source code, for "educational" purposes. To obtain a working build, go to <a href="http://www.rarewares.org/mp3-lame-bundle.php" target="_blank">RareWares</a> and download the latest package appropriate for your operating system, whether Windows, Linux or MacOS. As of this writing, the latest build is LAME 3.98.4.</p>
<p>Once installed, the LAME encoder accepts dozens of <a href="http://lame.cvs.sourceforge.net/viewvc/lame/lame/doc/html/switchs.html" target="_blank">parameters</a>. A typical command-line operation looks like this:</p>
<pre>lame mysong.wav mysong.mp3 -b 128 -h --verbose<br /></pre>
<p>This example takes the input file, <em>mysong.wav</em>, and generates a 128 kbps bitrate MP3 audio file, <em>mysong.mp3</em>, using a "high-quality" (-h) encoding algorithm. The <em>--verbose</em> parameter simply provides more feedback, useful for troubleshooting and more entertaining than a blank screen.</p>
<p>Now, assuming that you will always create a 128 kbps bitrate file and employ the same encoding algorithm, we can further simplify this operation by copying the command into a batch program file. On Windows, this is simply a text file with the .BAT extension. For example, the following batch file is called <em>encode.bat</em> and contains one command-line statement:</p>
<pre>lame %1 %2 -b 128 -h --verbose</pre>
<p>Now, we can invoke this batch file with this command:</p>
<pre>encode mysong.wav mysong.mp3<br /></pre>
<p>...and the result is identical to that of our first example <em>(but with less effort)</em>. In DOS and Windows, any parameters supplied at the command-line are automatically represented in the batch file by variables %1, %2, %3, etc. We can pass as many parameters as we like and Windows will automatically enumerate them.</p>
<p>Now, assuming that our copyright information won't change much from one song to the next, let's improve our batch operation with Creative Commons' recommended copyright parameters:</p>
<pre>lame %1 %2 -b 128 -h --verbose --tv "TCOP=2011, MyBand. Some Rights Reserved. Licensed to the public under http://creativecommons.org/licenses/by-nc-nd/3.0/us/. Verify at http://www.mywebsite.com/downloads/%3/." --tv "WCOP=http://creativecommons.org/licenses/by-nc-nd/3.0/us/" --tv "WOAF=http://www.mywebsite.com/downloads/%3/"</pre>
<p>Now, we can invoke the batch file with this command:</p>
<pre>encode mysong.wav mysong.mp3 mysong</pre>
<p>...and we'll receive an MP3 audio file, <em>mysong.mp3</em>, with the following copyright tag frames and values:</p>
<ul>
<li>TCOP: <em>2011, MyBand. Some Rights Reserved. Licensed to the public under
http://creativecommons.org/licenses/by-nc-nd/3.0/us/. Verify at
http://www.mywebsite.com/downloads/mysong/.</em></li>
<li>WCOP: <em>http://creativecommons.org/licenses/by-nc-nd/3.0/us/</em></li>
<li>WOAF: <em>http://www.mywebsite.com/downloads/mysong/</em></li>
</ul>
<h3>Just Tagging</h3>
<p>Alternately, if you've already got your MP3 audio file in hand and merely wish to insert the required copyright tag frames, then you can employ the same automation with a dedicated command-line tagging tool, such as Mark Schoolderman's "mass tagger," <a href="/assets/content/id3-078w.zip" target="_blank">ID3.exe</a>. <em>[If you re-tag your MP3 audio file with LAME, the audio will be unnecessarily re-encoded, degrading quality.]</em></p>
<p>For example, this batch program - I've saved it as <em>retag.bat </em>- performs the same copyright tagging operations as above, but on an MP3 audio file, using the aforementioned ID3.exe command-line tagger:</p>
<pre>mp3 -2 -wTCOP "2011, MyBand. Some Rights Reserved. Licensed to the public under http://creativecommons.org/licenses/by-nc-nd/3.0/us/. Verify at http://www.mywebsite.com/downloads/%2/." -wWCOP "http://creativecommons.org/licenses/by-nc-nd/3.0/us/" -wWOAF "http://www.mywebsite.com/downloads/%2/" %1<br /></pre>
<p>The batch program file is invoked with this command:</p>
<pre>retag mysong.mp3 mysong<br /></pre>
<p>Note that there are only two parameters in this batch program file. In this case, the specified MP3 audio file, mysong.mp3, is overwritten with the updated file.</p>
<p>Needless to say, you can take this batch automation to all sorts of extremes, creating command-line parameters for the band name, year of copyright, encoding bitrate and more. And for all of those other things that don't change from song to song, you can embed many of them automatically into every MP3 audio file you produce, with ID3 tag frames like WOAR (official artist/performer web page), WCOM (commercial information web page), and WPUB (publisher's official web page). Again, there are over 80 pre-defined tag frames to consider and new tag frames being added with each new ID3 revision.</p>
<h3>Double-check Your Work</h3>
<p>This warning deserves stern repeating: Before sharing your MP3 audio file with anyone, be sure to verify the content of its TCOP, WCOP and WOAF ID3 tag frames in a dedicated tagging application, like the aforementioned Mp3tag. To that end, know your tagging app and, particularly, how it presents the TCOP, WCOP and WOAF fields.</p>
<p>Once you release your MP3 audio file into the wild, there's no "take backs." While you might be able to replace those uploaded to music sharing sites and social networks with updated versions, there's no guarantee that your original, flawed tracks won't tour the Internet forever.</p>
<h3>Moving On<br /></h3>
<p>Now that we've identified where the example audio file's official download and verification page will be located, <em>http://www.mywebsite.com/downloads/mysong/, </em>we must create that page and add it to our website. In Part 3 of this article, we will discuss this second and final step of the Creative Commons licensing process, beginning with an introduction to Universal Resource Names (URNs) and the Base32-encoded SHA1 hash algorithm.</p>
<p>Don't quit on me now, Ringo. We're almost there.</p>
A Musician's Guide to Creative Commons, Part 1
urn:uuid:12DDAEE2-7E98-2630-CB5520BD429E0A11
2011-05-16T03:05:00Z
2011-06-09T10:06:00Z
<p><img style="float: right;" src="/assets/content/images/cc_logo.gif" alt="Creative Commons Logo" width="200" height="200" />For musicians who offer free music downloads, Creative Commons
represents a simple, free alternative to traditional copyright
registration. No tedious forms. No filing fees. No waiting. It's
instant, no-cost copyright goodness. What's more, the protections
offered by Creative Commons are flexible, to allow for certain uses of
your music, such as remixing or incorporation into commercial or
non-commercial video and other derivative works, <em>if </em>that's what
you want. This is a boon for DIY musicians whose traditional '©' and
'circle-P' symbols tell DJs, podcasters and filmmakers, "hands off my
music." And so, they use somebody else's music instead. Opportunity
lost.</p>
<p>On the downside, implementing Creative Commons <em>properly</em> isn't
entirely straightforward, and the examples demonstrated on the org's
website are highly technical, aimed squarely at developers. Assuming
that your drummer is also your "web guy" and that he doesn't know an MP3
ID3 tag frame from an SHA1 hash, a little help here could go a long
way. Let's jam.</p>
Dave Delbridge
<p><img style="float: right;" src="/assets/content/images/cc_logo.gif" alt="Creative Commons Logo" width="200" height="200" />For musicians who offer free music downloads, Creative Commons represents a simple, free alternative to traditional copyright registration. No tedious forms. No filing fees. No waiting. It's instant, no-cost copyright goodness. What's more, the protections offered by Creative Commons are flexible, to allow for certain uses of your music, such as remixing or incorporation into commercial or non-commercial video and other derivative works, <em>if </em>that's what you want. This is a boon for DIY musicians whose traditional '©' and 'circle-P' symbols tell DJs, podcasters and filmmakers, "hands off my music." And so, they use somebody else's music instead. Opportunity lost.</p>
<p>On the downside, implementing Creative Commons <em>properly</em> isn't entirely straightforward, and the examples demonstrated on the org's website are highly technical, aimed squarely at developers. Assuming that your drummer is also your "web guy" and that he doesn't know an MP3 ID3 tag frame from an SHA1 hash, a little help here could go a long way. Let's jam.</p>
<h3>Disclaimer<br /></h3>
<p>Before we continue, understand that I am not an attorney and that none of the information presented in this article should be construed as legal advice. The information presented here is meant to introduce an optional copyright method but without suggesting its suitability for any particular purpose. Use this information at your own risk. For copyright advice, consult an experienced entertainment lawyer.</p>
<p>Also, please note that certain statements and examples presented in this article are particular to the laws and government of the United States of America. Musicians operating in other countries should be mindful of their local requirements.</p>
<h3>What is Creative Commons?</h3>
<p>In simple, drummer-friendly terms, Creative Commons is a non-profit organization that has crafted a series of easy-to-understand usage licenses that are free to ascribe to your music files. Each license has a friendly, human-readable version, backed by a not-so-friendly lawyer-readable version. Take, for example, this Creative Commons license, specified in many of my own freely downloadable MP3 audio files:</p>
<p>
<a title="Creative Commons Attribution-Noncommercial 3.0 United States License" href="http://creativecommons.org/licenses/by-nc/3.0/us/" target="_blank"><img style="margin-top: 20px; margin-bottom: 20px;" src="/assets/content//cc-by-nc-500.jpg" alt="Creative Commons Attribution-Noncommercial 3.0 United States License" width="500" height="628" /></a></p>
<ul>
</ul>
<p>This is a screen capture of the human-readable version of the license
<em>(located at <a href="http://creativecommons.org/licenses/by-nc/3.0/us/" target="_blank">http://creativecommons.org/licenses/by-nc/3.0/us/</a>)</em>. At the
bottom of the license, you'll find a link to the actual license - the
"legal code."</p>
<p>As of this writing, there are six licenses to choose from (and a "public domain" license), each incorporating one or more of these four basic conditions:</p>
<ul>
<li><strong>Attribution (abbreviated, "BY") </strong>- requires that any copies or derivative works (if allowed) provide proper credit to the owner of the original work. For example, if a podcast incorporates your music in its opening title sequence, the producer <em>must </em>credit you <em>in the podcast</em>.</li>
<li><strong>Share-Alike ("SA") </strong>- requires that any derivative works (if allowed) employ the same Creative Commons license. In this manner, you may preclude commercial use of your music in remixes, for example, or require that remixes may be made of remixes.</li>
<li><strong>Non-Commercial ("NC") </strong>- prohibits copies, derivatives and redistribution in conjunction with any commercial activity.</li>
<li><strong>No Derivative Works ("ND") </strong>- allows others to create, redistribute and perform only verbatim copies of the work.</li>
</ul>
<p>So, for example, the aforementioned Creative Commons Attribution Non-Commercial license (abbreviated, "CC BY-NC") employs the <em>Attribution</em> and <em>Non-Commercial </em>conditions, while omitting the <em>Share-Alike </em>and <em>No Derivative Works </em>conditions. As such, others may remix and incorporate my CC BY-NC-licensed music into a film or video project, but only for non-commercial display and redistribution. Also, without the <em>Share-Alike</em> condition, those filmmakers needn't employ the same CC BY-NC license. They may, for example, employ a more restrictive CC BY-NC-ND license, to prevent further modification of their film. <em>[In case you're wondering, they may not employ a less-restrictive license to undermine the Non-Commercial condition of my original license. This isn't clear in the human-readable version but clarified in the license's legal code.]</em></p>
<p>Mix and match these conditions and you'll discover six logical license combinations. They're pretty obvious, but for a complete description of the six licenses and their conditions, visit <a href="http://creativecommons.org/about/licenses/" target="_blank">Creative Commons' About Licenses page</a>. Furthermore, additional conditions and license types may be introduced in the future, so be sure to check with Creative Commons for the latest updates.</p>
<h3>What Does Creative Commons <em>NOT </em>Do?<br /></h3>
<p>It's worth emphasizing that none of the Creative Commons licenses
prohibit copying or redistribution outright. For this level of "All
Rights Reserved" old-skool control <em>(and RIAA-style paranoia)</em>, use
traditional Copyright instead.</p>
<p>Furthermore, Creative Commons does not offer any copyright registration services - they neither timestamp nor catalogue your music in a central database. Should the originality of your work be challenged, you'll not have a central authority to turn to for verification of your music submission or registration date. And while alternatives do exist, they are uncertain, at best. For example, you might upload your song file to the <a href="http://www.archive.org" target="_blank">Internet Archive</a> but with few guarantees that the file <em>(or the organization)</em> will survive, unaltered over time. As such, the reliability of such evidence is questionable and may offer no worthwhile legal support. As of this writing, there appear to be no trusted / bonded third-party registration solutions, as were once provided by the now-defunct National Academy of Songwriters' SongBank service.</p>
<p>Lastly, a Creative Commons license might not jive with your other contractual obligations. For example, your music publisher or performing rights organization <em>(e.g., ASCAP, BMI, SESAC)</em>, if you work with one, may require that your songs be registered with the U.S. Copyright Office, for example, in order to perform its regular duties. Such obligations might not preclude also releasing a Creative Commons-licensed music file, but then the effort- and cost-saving benefits of Creative Commons are largely wasted.</p>
<p>On the upside, just as with traditional Copyright, a Creative Commons license does not preclude
further licensing of the CC-licensed work. You may, for example,
authorize commercial use of your music by a particular studio for use in a film, even though
the music is already licensed to the public under a CC BY-NC
<em>(non-commercial)</em> license.</p>
<h3>Next Stop: How to Implement Creative Commons<br /></h3>
<p>Correct application of a Creative Commons license, as recommended by the organization, entails two distinct steps. First, you must label, or "tag," your audio file with the necessary Creative Commons information. Then, you should create and publish a file download and verification page on your web site.</p>
<p>We'll discuss the first of these steps, file tagging, in Part 2 of this article. And, yes, we'll be gettin' technical, so bring your MP3s and eye protection. And your drummer.</p>
How To Pass Multiple Name/Value Pairs from ColdFusion to jQuery
urn:uuid:A27385F4-7E98-2630-CEC97530B5FE5CCB
2011-04-29T10:04:26Z
2011-04-30T03:04:00Z
<p>ColdFusion and jQuery complement each other quite nicely. The first
facilitates all manner of back-end über-awesomeness while the other,
comparatively new kid on the block, puts some bling on your front-end,
so to speak. Thankfully, getting these two to share data through
Document Object Model (DOM) elements is easy, if altogether
undocumented. And by <em>"undocumented,"</em> I of course mean that it's
well-documented, but in nomenclature that evaded this seasoned
ColdFusion developer for hours of tedious Google searching.</p>
Dave Delbridge
<p>ColdFusion and jQuery complement each other quite nicely. The first facilitates all manner of back-end über-awesomeness while the other, comparatively new kid on the block, puts some bling on your front-end, so to speak. Thankfully, getting these two to share data through Document Object Model (DOM) elements is easy, if altogether undocumented. And by <em>"undocumented,"</em> I of course mean that it's well-documented, but in nomenclature that evaded this seasoned ColdFusion developer for hours of tedious Google searching.</p>
<p>In a word, the solution is <em>"<a href="http://dev.w3.org/html5/spec/elements.html#embedding-custom-non-visible-data-with-the-data-attributes" target="_blank">custom data attributes</a>."</em> Okay, that's three words, but still shorter than the technical alternative: <em>"custom non-visible data-* attributes."</em> New in HTML 5, we are permitted to litter our HTML tags with all manner of custom parameters. In fact, any parameter beginning with <em>"data-"</em> and at least one additional alphanumeric character is fair game. And if you've ever wanted to cram two or more name/value pairs into
an ID or CLASS parameter, then you already know just how valuable this addition can be.</p>
<p>In practice, it looks like this:</p>
<pre><span class="tag"><ul</span><span class="tag"> id="books"></span><span class="pln"><br /> </span><span class="tag"><li class="inventory" data-sold=</span><span class="atv">"63"</span><span class="tag"> data-unsold=</span><span class="atv">"57"</span><span class="tag">></span><span class="pln">jQuery Cookbook</span><span class="tag"></li></span><span class="pln"><br /> </span><span class="tag"><li class="inventory" data-sold=</span><span class="atv">"97"</span><span class="tag"> data-unsold=</span><span class="atv">"13"</span><span class="tag">></span><span class="pln">JavaScript, the Definitive Guide</span><span class="tag"></li></span><span class="pln"><br /> </span><span class="tag"><li class="inventory" data-sold=</span><span class="atv">"16"</span><span class="tag"> data-unsold=</span><span class="atv">"12"</span><span class="tag">></span><span class="pln">Adobe ColdFusion Anthology</span><span class="tag"></li></span><span class="pln"><br /></span><span class="tag"></ul></span><span class="pln"> </span></pre>
<p>...and with jQuery's <em>.attr()</em> method, you can pull the parameters, <em>data-sold </em>and <em>data-unsold</em>,<em> </em>into your script in order to perform all manner of logical operations. Maybe your favorite jQuery plugin will crunch the data into an <a href="http://www.reynoldsftw.com/2009/02/6-jquery-chart-plugins-reviewed/" target="_blank">interactive chart</a>.</p>
<h3>SAMPLE ColdFusion CODE: Pre-jQuery<br /></h3>
<p>Now that I've spoiled the surprise, you're probably dashing off to your stalled code and a fresh energy drink. But for those who've chosen to stick around, even if only to be polite, I'll demonstrate ColdFusion-to-jQuery communication with a simple form - it's an inventory re-ordering form that performs two simple functions:</p>
<ul>
<li>Queries a database for all inventory items</li>
<li>Displays a text input form field for each item, where staff can submit item re-order quantities.</li>
</ul>
<p>Omitting the HTML framework and ignoring any syntactical errors<em> - the code is untested -</em> our template looks like this<span class="green"></span>:</p>
<pre><!--- ************************************************************ ---><br /><!--- Get inventory items, descriptions, quantity on hand, and ---><br /><!--- calculated quantity sold over last 30 days. ---><br /><!--- ************************************************************ ---><br /><br /><cfquery name="Get_Items" datasource="#MyDSN#"><br /> SELECT Items.Item_ID, Items.Name, Items.Qty_Unsold, COUNT(Sales.Item_ID) AS Qty_Sold<br /> FROM Items LEFT OUTER JOIN<br /> Sales ON Items.Item_ID = Sales.Item_ID<br /> WHERE Sales.Timestamp >= <cfqueryparam value="#Now()-30#" cfsqltype="cf_sql_timestamp"><br /> ORDER BY Name<br /></cfquery><br /><br /><!--- ************************************************************ ---><br /><!--- Display re-order form ---><br /><!--- ************************************************************ ---><br /><br /><form action="re_order_items.cfm" method="post"><br /><br /> <cfoutput query="Get_Items"><br /><span class="unstyled"> <br class="unstyled" /> #Get_Items.Name#: <input class="inventory" type="text" name="Item_#Get_Items.Item_ID#" value="#Get_Items.Qty_Sold#"><br /><br /> </span><br /> </cfoutput><br /> <br /> <input type="submit" name="Submit" value="submit"><br /><br /></form><br /></pre>
<h3>Sample CF Code: With Custom Data Attributes and jQuery<br /></h3>
<p>Now, let's throw some jQuery into the mix. If the user submits a re-order value that is too low to meet historical demand, then we'll turn the background of the form field red, warning the user to increase the re-order volume. To do this, our very simple jQuery script will require two additional parameters from each ColdFusion-generated <em><input class="inventory"></em> element: the quantity on hand <em>(#Get_Items.Qty_Unsold#)</em> and the quantity sold in the last 30 days <em>(#Get_Items.Qty_Sold#)</em>.</p>
<p>Inserting two custom data attributes and a little jQuery produces the updated code block, below. For your convenience, changes from the prior code block are denoted in <span class="red">red</span>.</p>
<pre><!--- ************************************************************ ---><br /><!--- Get inventory items, descriptions, quantity on hand, and ---><br /><!--- calculated quantity sold over last 30 days. ---><br /><!--- ************************************************************ ---><br /><br /><cfquery name="Get_Items" datasource="#MyDSN#"><br /> SELECT Items.Item_ID, Items.Name, Items.Qty_Unsold, COUNT(Sales.Item_ID) AS Qty_Sold<br /> FROM Items LEFT OUTER JOIN<br /> Sales ON Items.Item_ID = Sales.Item_ID<br /> WHERE Sales.Timestamp >= <cfqueryparam value="#Now()-30#" cfsqltype="cf_sql_timestamp"><br /> ORDER BY Name<br /></cfquery><br /><br /><!--- ************************************************************ ---><br /><!--- Display re-order form ---><br /><!--- ************************************************************ ---><br /><br /><form action="re_order_items.cfm" method="post"><br /><br /> <cfoutput query="Get_Items"><br /> <br /> #Get_Items.Name#: <input class="inventory" <span class="red">data-qty-unsold="#Get_Items.Qty_Unsold#" data-qty-sold="#Get_Items.Qty_Sold#"</span> type="text" name="Item_#Get_Items.Item_ID#" value="#Get_Items.Qty_Sold#"><br /><br /> <br /> </cfoutput><br /> <br /> <input type="submit" name="Submit" value="submit"><br /><br /></form><br /><br /><span class="red"><!--- ************************************************************ ---><br /><!--- When changing any input field (item reorder volume), com- ---><br /><!--- pare against volume sold in last 30 days and unsold stock ---><br /><!--- on hand to be sure we can meet demand this month. If ---><br /><!--- lower than the difference of volume sold and stock on ---><br /><!--- hand, then turn the background of the input field red via ---><br /><!--- Cascading Style Sheets (CSS) class '.red', defined in ---><br /><!--- main.css. ---><br /><!--- ************************************************************ ---><br /><br /><script><br /> $(".inventory").change(function () {<br /> var qtySold = $(this).attr('data-qty-sold');<br /> var qtyUnsold = $(this).attr('data-qty-unsold');<br /> var qtyMinimum = qtySold - qtyUnsold;<br /> if($(this).val() < qtyMinimum) {<br /> $(this).toggleClass("red", 1);<br /> }<br /> else {<br /> $(this).toggleClass("red", 0);<br /> }<br /> });<br /></script></span><br /></pre>
<p>That's all there is to it. And, in the interest of completeness, should you wish to store values calculated in jQuery back into your DOM element, simply use jQuery's <em>.attr()</em> method again. Not only can this method update existing attributes, but can also create new attributes on the fly, for a veritable deluge of "data-*" parameters. Go crazy.</p>
<p>I hope this information has been helpful. If so, you can follow me on Twitter at <a href="http://twitter.com/circa3000" target="_blank">@circa3000</a>. And, of course, please consider <a href="http://www.circa3000.com/" target="_blank">Circa 3000</a> for your ColdFusion hosting needs. I look forward to hearing from you!</p>
Optimizing Your ColdFusion Site for Commercial Hosting
urn:uuid:69AD3624-7E98-2630-C97E834A3B450834
2011-04-18T09:04:34Z
2011-04-18T03:04:00Z
<p>When moving your ColdFusion website to a commercial hosting provider,
between providers or even from an internal development server to your
own production server, problems may arise from inconsistencies between
the two locations; problems that are most easily remedied by that
proverbial, cruel, mocking <em>"ounce of prevention."</em></p>
<p>Relocating a site between hosts already implies downtime and frazzled
nerves. The last thing you need in this situation is a slew of fresh
page errors. Here are some very simple tips for improving the
portability of your ColdFusion site.</p>
Dave Delbridge
<p>When moving your ColdFusion website to a commercial hosting provider, between providers or even from an internal development server to your own production server, problems may arise from inconsistencies between the two locations; problems that are most easily remedied by that proverbial, cruel, mocking <em>"ounce of prevention."</em></p>
<p>Relocating a site between hosts already implies downtime and frazzled nerves. The last thing you need in this situation is a slew of fresh page errors. Here are some very simple tips for improving the portability of your ColdFusion site.</p>
<h3>"What Could Go Wrong?"<br /></h3>
<p>So, what might <em>"go boom" </em>when moving your ColdFusion site from one server to another? To begin with, the physical path to your hosted files (e.g., D:\my_site\www\) will almost certainly change between commercial hosts, effectively breaking any of your ColdFusion templates that employ CFFile, CFDirectory, CFDocument or any other tag that specifies a physical path parameter <em>(e.g., "file='D:\my_site\docs\report.pdf'")</em>.</p>
<p>Furthermore, and particularly in shared hosting environments, popular data source names <em>(e.g., "dsn") </em>and mappings <em>(e.g., "/include") </em>may prove to be unavailable. As such, alternates must be specified in ColdFusion Administrator, effectively breaking all of your ColdFusion templates that contain a <em>CFQuery</em> tag <em>- that's most of them, right? - </em>and any referencing your mapped directories. <em>For myself, that's all umpteen-thousand </em><em>of them</em>. And that's a lot of search-and-replace. Under duress. Good luck.</p>
<p>For the purpose of demonstration, the following code snippet represents a typical ColdFusion form handler; in this case, an image uploader, as may be found on Flickr or Facebook. In short, an image is uploaded to the server by way of a form field and its filename recorded into a database. For tidiness, common HTML components are rendered in the included templates <em>header.cfm </em>and <em>footer.cfm</em> found in <em>"E:\Delbridge_Org\www\include\."</em> Because ColdFusion doesn't allow absolute paths in CFInclude statements, that directory is mapped to <em>- you guessed it -</em> <em>"/include."</em></p>
<p>In fact, the code logic is unimportant while serving up a nice example of the three common trouble spots described above.<em><br /></em></p>
<pre><!--- ************************************************************* ---><br /><!--- Include page header ---><br /><!--- ************************************************************* ---><br /><br /><cfinclude template="/include/header.cfm"><br /><br /><!--- ************************************************************* ---><br /><!--- Index the uploaded image ---><br /><!--- ************************************************************* ---><br /><br /><cfset Timestamp = DateFormat(Now(),'mmddyyyy') & TimeFormat(Now(),'hhmmss')><br /><br /><cfquery name="Index_Image" datasource="dsn"><br /> INSERT INTO GIFs (Filename)<br /> VALUES ('#Timestamp#.gif')<br /></cfquery><br /><br /><!--- ************************************************************* ---><br /><!--- Upload the specified file ---><br /><!--- ************************************************************* ---><br /><br /><cffile action="upload"<br /> filefield="form.Filename"<br /> destination="E:\Delbridge_Org\uploads\images\#Timestamp#.gif"<br /> nameconflict="overwrite"><br /><br /><!--- ************************************************************* ---><br /><!--- Include page footer ---><br /><!--- ************************************************************* ---><br /><br /><cfinclude template="/include/footer.cfm"></pre>
<p>When the site employing this template is ported to another host, these ColdFusion statements will require maintenance if the physical path changes <em>- it most certainly will -</em> or the specified mappings or data source name are already in use by another hosting customer.</p>
<h3>"More Better" Portability<br /></h3>
<p>To protect ourselves, the solution is to simply encapsulate these environmental inconsistencies into variables defined clearly in your root <em>application.cfm</em> template and then use those variables in place of absolute declarations throughout your site. Here's the <em>application.cfm </em>file we might use with the aforementioned example:</p>
<pre><!--- ************************************************************ ---><br /><!--- Define site-wide portability parameters ---><br /><!--- ************************************************************ ---><br /><br /><cfset DSN = "Delbridge_Blog"><br /><cfset Disk = "E:"><br /><cfset Root = "Delbridge_Org"><br /><cfset Include = "/my_unique_include"><br /></pre>
<p>Now, the aforementioned form handler may be recomposed to look like this:</p>
<pre><!--- ************************************************************* ---><br /><!--- Include page header ---><br /><!--- ************************************************************* ---><br /><br /><cfinclude template="#Include#/header.cfm"><br /><br /><!--- ************************************************************* ---><br /><!--- Index the uploaded image ---><br /><!--- ************************************************************* ---><br /><br /><cfset Timestamp = DateFormat(Now(),'mmddyyyy') & TimeFormat(Now(),'hhmmss')><br /><br /><cfquery name="Index_Image" datasource="#DSN#"><br /> INSERT INTO GIFs (Filename)<br /> VALUES ('#Timestamp#.gif')<br /></cfquery><br /><br /><!--- ************************************************************* ---><br /><!--- Upload the specified file ---><br /><!--- ************************************************************* ---><br /><br /><cffile action="upload"<br /> filefield="form.Filename"<br /> destination="#Disk#\#Root#\uploads\images\#Timestamp#.gif"<br /> nameconflict="overwrite"><br /><br /><!--- ************************************************************* ---><br /><!--- Include page footer ---><br /><!--- ************************************************************* ---><br /><br /><cfinclude template="#Include#/footer.cfm"><br /><br /></pre>
<p>...and when I decide to change hosting providers again<em> - perish the thought -</em> those parameters may change on me without inducing panic. A quick update to the <em>application.cfm </em>file is all that is needed to morph my entire site into compliance with the host's ColdFusion hosting requirements.</p>
<p>Needless to say, these represent only the most common environmental inconsistencies a ColdFusion developer might stumble over. One may, of course, carry this principle to everything from Verity and Solr collections to Scheduled Tasks - any user-defined server resource that might decline your first choice of instance names.</p>
<p>Lastly, this practice affords developers one additional benefit: that of consistency. For those power-coders who juggle many ColdFusion development projects at once, when you employ this simple strategy across all of them, you need no longer fumble for the right physical path, the right data source name or the correct mapping again. For every site, "#DSN#" is the correct data source, "#Include#" the correct mapping, and "#Disk#\#Root#" the correct physical path.</p>
<p>I hope this information has been helpful. If so, you can follow me on Twitter at @circa3000. And please consider Circa 3000 for your ColdFusion hosting needs. I look forward to hearing from you!</p>
Tracking Japan's Nuclear Radiation
urn:uuid:C7A1CD4E-7E98-2630-CD23C935B7483F26
2011-03-17T09:03:20Z
2011-03-20T10:03:00Z
<p>Standing downwind from Japan's damaged nuclear reactors, its
understandable that some Americans have turned their nuclear radiation
panic dials to "11." Misinformation published on the Internet has only
compounded the problem. Thankfully, The New York Times has published an
<a href="http://www.nytimes.com/interactive/2011/03/16/science/plume-graphic.html?ref=science" target="_blank">animated computer model</a>
that predicts "extremely minor health consequences." And now that we
have a weather prediction, all we need is a real-time radiation weather
map.</p>
<p>Unfortunately, there is no such thing as a "radiation weather map." So instead, let's grab some real-time EPA data and throw it into Microsoft Excel....</p>
Dave Delbridge
<p>Standing downwind from Japan's damaged nuclear reactors, its understandable that some Americans have turned their nuclear radiation panic dials to "11." Misinformation published on the Internet has only compounded the problem. Thankfully, The New York Times has published an <a href="http://www.nytimes.com/interactive/2011/03/16/science/plume-graphic.html?ref=science" target="_blank">animated computer model</a> that predicts "extremely minor health consequences." And now that we have a weather prediction, all we need is a real-time radiation weather map.</p>
<ul>
</ul>
<p>Unfortunately, there is no such thing as a "radiation weather map." However, near-real time reports of current radiation levels at various points in the United States are available from:</p>
<ul>
<li> RadNet, at the Environmental Protection Agency's (EPA) <a href="http://cdx.epa.gov/EPA_Home.asp" target="_blank">Central Data Exchange</a> (CDX) website</li>
<li>The private, publicly-driven <a href="http://www.radiationnetwork.com/" target="_blank">Radiation Network</a></li>
<li>The private, publicly-driven <a title="Online Geiger Counter Nuclear Radiation Detector Map" href="http://www.blackcatsystems.com/RadMap/map.html" target="_blank">Online Geiger Counter Nuclear Radiation Detector Map</a> at Black Cat Systems</li>
</ul>
<p>The first requires an elaborate <a href="http://www.epa.gov/narel/radnet/pdf/How_to_Access_RadNet_Data.pdf" target="_blank">registration process</a>. The others are immediately available but provide no historical data to suggest natural radiation levels and useful trends. As such, some visitors are panicked by the sites' reports of innocuous radiation levels.</p>
<p><a title="Online Geiger Counter Nuclear Radiation Detector Map at Black Cat Systems" href="http://www.blackcatsystems.com/RadMap/map.html" target="_blank"><img src="/assets/content//images/radiation_blackcat.gif" alt="Online Geiger Counter Nuclear Radiation Detector Map" width="500" height="388" /></a></p>
<p>According to the aforementioned animated computer model, the Sierra Mountains (where I live, thank you) are likely to see the first and strongest detectable traces of radioactive fallout, should there be any. Unfortunately, none of these radiation tracking services collects data from the Sierra Mountains. A RadNet installation at Reno, Nevada is presently offline.</p>
<p>With historical data from the CDX, I've charted ambient radiation levels for San Francisco and Sacramento in Microsoft's Excel, presented below. Data prior to March 11th offers a baseline of typical radiation levels and daily fluctuations. If you've gotten yourself into RadNet and would like to roll your own, perhaps for another city, be sure to format the X-axis (date and time), with axis type "Text axis." By default, Microsoft Excel determines axis types by data but discards time values from date/time strings, making a mess of things. Fortunately, the CDX data occurs at regular 1-hour intervals and may therefore be safely treated as text values without skewing the time relationship between chart points.</p>
<p><a title="Ambient Radiation - San Francisco" href="/assets/content//images/radiation_sf.gif" target="_blank"><img style="border: 1px solid black;" src="/assets/content//images/radiation_sf.gif" alt="Ambient Radiation - San Francisco" width="500" height="364" /></a></p>
<p><a title="Ambient Radiation - Sacramento" href="/assets/content//images/radiation_sac.gif" target="_blank"><img style="border: 1px solid black;" src="/assets/content//images/radiation_sac.gif" alt="Ambient Radiation - Sacramento" width="500" height="364" /></a></p>
<p>Click on either of these images to reveal a full-size view. <strong>Images last updated 3/19/2011 4:23 PM PST. </strong>Returning visitors, be sure to refresh your browser cache. <strong>No longer updated - please see "UPDATE" and comments, below.</strong></p>
<p>To read the charts, understand that the CDX divides the radiation spectrum into ten contiguous ranges for analysis. Each has its own natural range and danger level. Not being a nuclear physicist, I can't detail those with any professionalism and have found no reliable references online. According to some sources, we should be concerned only with ranges 9 and 10, which both have a natural occurrence of perhaps 50 radiation counts per minute (CPM) and become unhealthy at around 100 CPM. Again, these are only suggestions gleaned from unreliable sources. RadNet offers no suggestion of danger levels and recommends that we simply monitor the values for trends against historical data. I will try to update this chart daily until this situation settles, and more frequently if trends change or if web stats indicate more than a mild interest in this blog post.</p>
<p>I hope you find this information helpful. In closing, let me offer my sincerest condolences to the people of Japan and to everyone affected by this horrible tragedy. The Japanese people have demonstrated to the rest of the world an incredible level of honor and selflessness and deserve our greatest respect and support.</p>
<p><strong>UPDATE: </strong>By popular demand, RadNet has published very similar charts for most West Coast stations, with the advantages of a logarithmic scale, automatic updating, and thorough background information to answer most common questions. Presented below are their current renderings for Sacramento, San Francisco, Los Angeles and Honolulu. For other cities, visit <a title="RadNet Air Monitoring Data from the U.S. West Coast" href="http://www.epa.gov/radiation/rert/radnet-data.html" target="_blank">RadNet Air Monitoring Data from the U.S. West Coast</a>.</p>
<p>What remains unanswered? It would be nice to find an authoritative explanation of the specific radioactive nuclides relevant to this event, their respective charted ranges, and their accordant danger levels. It would also be nice to see the RadNet station at Reno, Nevada back online. While not ideally situated <em>behind </em>the Sierra, it nonetheless stands to receive the earliest and highest radiation readings in the country and could serve as <em>the </em>nationwide barometer, in my untrained opinion. [Better still would be monitors at altitude <em>in </em>the northwestern Sierra.] My sincere thanks go to the folks at RadNet for producing these charts.</p>
<p><a title="Gamma Radiation Gross Count Rate - San Francisco" href="http://www.epa.gov/radiation/rert/radnet-sanfrancisco-bg.html" target="_blank"><img style="border: 1px solid black;" src="https://cdxnode64.epa.gov/cdx-radnet-rest/service/graph?type=graph&startDate=03012011&radType=GAMMA&state=CA&city=San%20Francisco" alt="Gamma Radiation Gross Count Rate, San Francisco" width="500" /></a></p>
<p><a title="Gamma Radiation Gross Count Rate - Sacramento" href="http://www.epa.gov/radiation/rert/radnet-sacramento-bg.html" target="_blank"><img style="border: 1px solid black;" src="https://cdxnode64.epa.gov/cdx-radnet-rest/service/graph?type=graph&startDate=03012011&radType=GAMMA&state=CA&city=Sacramento" alt="Gamma Radiation Gross Count Rate, Sacramento" width="500" /></a></p>
<p><a title="Gamma Radiation Gross Count Rate - Los Angeles" href="http://www.epa.gov/radiation/rert/radnet-losangeles-bg.html" target="_blank"><img style="border: 1px solid black;" src="https://cdxnode64.epa.gov/cdx-radnet-rest/service/graph?type=graph&startDate=03012011&radType=GAMMA&state=CA&city=Los%20Angeles" alt="Gamma Radiation Gross Count Rate - Los Angeles" width="500" /></a></p>
<p><a title="Gamma Radiation Gross Count Rate - Honolulu" href="http://www.epa.gov/radiation/rert/radnet-honolulu-bg.html" target="_blank"><img style="border: 1px solid black;" src="https://cdxnode64.epa.gov/cdx-radnet-rest/service/graph?type=graph&startDate=03012011&radType=GAMMA&state=HI&city=Honolulu" alt="Gamma Radiation Gross Count Rate, Honolulu" width="500" /></a></p>
Tackling Twitter's OAuth with ColdFusion
urn:uuid:E9645476-7E98-2630-CC6DCB3D05CFED99
2010-10-26T09:10:00Z
2011-10-03T02:10:00Z
<p>In September of 2010, Twitter pulled the plug on Basic Authentication, imposing an open authorization (<a href="http://oauth.net/" target="_blank">OAuth</a>)
security protocol on application developers. The trouble with OAuth?
It's a wee bit complicated. Worse still, as of this writing, ColdFusion
is noticeably absent from Twitter's API wiki, offering no libraries or
examples to work from.</p>
<p>On the upside, a handful of ColdFusion solutions have surfaced, like the impressive <a href="http://twitter4j.org/en/index.html" target="_blank">Twitter4J Java library</a> and a <a href="http://oauth.riaforge.org/" target="_blank">component library</a>
adapted from PHP by Harry Klein. But, if you're new to OAuth, then you
may have found those solutions difficult to understand. Or perhaps
you'd rather roll your own. Either way, I thought it worthwhile to
compose an OAuth primer for ColdFusion developers. For the purposes of
education, the code samples are traditional and heavily commented. I
hope you find it helpful.</p>
Dave Delbridge
<p>In September of 2010, Twitter pulled the plug on Basic Authentication, imposing an open authorization (<a href="http://oauth.net/" target="_blank">OAuth</a>)
security protocol on application developers. The trouble with OAuth?
It's a wee bit complicated. Worse still, as of this writing, ColdFusion
is noticeably absent from Twitter's API wiki, offering no libraries or
examples to work from.</p>
<p>On the upside, a handful of ColdFusion solutions have surfaced, like the impressive <a href="http://twitter4j.org/en/index.html" target="_blank">Twitter4J Java library</a> and a <a href="http://oauth.riaforge.org/" target="_blank">component library</a>
adapted from PHP by Harry Klein. But, if you're new to OAuth, then you
may have found those solutions difficult to understand. Or perhaps
you'd rather roll your own. Either way, I thought it worthwhile to
compose an OAuth primer for ColdFusion developers. For the purposes of
education, the code samples are traditional and heavily commented. I
hope you find it helpful.</p>
<h3>introduction to Twitter's oauth<br /></h3>
<p>Before we begin, please read Twitter's "<a href="http://dev.twitter.com/pages/auth">Authenticating Requests with OAuth</a>."
The page supplies important background information, preliminary
requirements, a beautiful <a href="http://a0.twimg.com/images/dev/oauth_diagram.png" target="_blank">workflow diagram</a>, and indispensable
step-by-step instructions with sample data. It is the blueprint from
which this ColdFusion-specific document is built. Each of the diagram's
steps, A through G, are mirrored here.</p>
<p>If you're rolling your own code from scratch, I recommend the OAuth signature checker at <a href="http://quonos.nl/oauthTester/" target="_blank">http://quonos.nl/oauthTester/</a> and the OAuth signature generator at <a href="http://oauth.googlecode.com/svn/code/javascript/example/signature.html" target="_blank">http://oauth.googlecode.com/svn/code/javascript/example/signature.html</a>.
Composing a valid signature base string is perhaps OAuth's toughest
puzzle and Twitter's only response to malformed base strings is the
vague "Failed to validate oauth signature and token." As such, these
validators can be indispensible.</p>
<h3>Things To Watch Out For</h3>
<p>Before diving into the details, here are some stumbling blocks to be aware of:</p>
<ul>
<li>ColdFusion's <em>URLEncodedFormat </em>function is not 100% compliant with RFC 3986 and will trip up OAuth's sensitive string calculations. For details and a workaround, read "<a href="http://cookbooks.adobe.com/post_URL_encoding_to_RFC_3986-17970.html" target="_blank">URL Encoding to RFC 3986</a>" in Adobe's Developer Connection.</li>
<li>Contrary to ColdFusion's documentation, HMAC-SHA1 is not supported
by the Encrypt (or Hash) functions. The workaround is a simple <a href="http://www.coldfusiondeveloper.com.au/go/note/2008/01/18/hmac-sha1-using-java/" target="_blank">HMAC-SHA1 CFFunction</a>.</li>
<li>In accordance with the OAuth specification, the callback URL is <em>twice </em>URL encoded. <em>[In fact, all parameters in the base string are twice URL encoded, though often unaffected.]</em> This is a common source of confusion when analyzing base strings.</li>
<li>ColdFusion's <em>URLEncodedFormat() </em>function produces incompatible strings when international characters are introduced, even with the <em>charset="utf-8" </em>parameter. To correct, use the <em><cfprocessingdirective pageEncoding="utf-8"></em> tag.</li>
<li>OAuth was made for structures. [Or is it the other way around?]
Unfortunately, ColdFusion automatically converts structure keys to
uppercase when using dot notation (e.g., MyStruct.MyKey). To maintain
case, use bracketed notation instead, a la MyStruct["MyKey"].</li>
</ul>
<h3>The Functions</h3>
<p>For efficiency and clarity, this project employs four functions. Put them in a <em>"_functions"</em> directory (or update the <em>cfinclude</em> statements in each template, accordingly). They are:</p>
<p><strong>hmac_sha1(): </strong>Generates the HMAC-SHA1 authentication code required by OAuth.</p>
<pre><!--- ************************************************************ ---><br /><!--- HMAC-SHA1 AUTHENTICATION CODE FUNCTION ---><br /><!--- ---><br /><!--- Contrary to ColdFusion's docs, the Encrypt() and Hash() ---><br /><!--- functions do not support HMAC-SHA1 as required by this ---><br /><!--- project. This function, provided by Dmitry Yakhnov of ---><br /><!--- Yakhnov Studio (http://www.coldfusiondeveloper.com.au/) ---><br /><!--- takes advantage of Java's native support for HMAC-SHA1. ---><br /><!--- Thank you for sharing, Dmitry! ---><br /><!--- ---><br /><!--- PARAMETERS ---><br /><!--- signKey (string) = Secret key ---><br /><!--- signMessage (string) = Message to be hashed ---><br /><!--- ---><br /><!--- RETURNS ---><br /><!--- (binary) The keyed authentication code ---><br /><!--- ---><br /><!--- ************************************************************ ---><br /><br /><cffunction name="HMAC_SHA1" returntype="binary" access="public" output="no"><br /><br /> <cfargument name="signKey" type="string" required="true" /><br /> <cfargument name="signMessage" type="string" required="true" /><br /><br /> <cfset var jMsg = JavaCast("string",arguments.signMessage).getBytes("iso-8859-1") /><br /> <cfset var jKey = JavaCast("string",arguments.signKey).getBytes("iso-8859-1") /><br /><br /> <cfset var key = createObject("java","javax.crypto.spec.SecretKeySpec") /><br /> <cfset var mac = createObject("java","javax.crypto.Mac") /><br /><br /> <cfset key = key.init(jKey,"HmacSHA1") /><br /><br /> <cfset mac = mac.getInstance(key.getAlgorithm()) /><br /> <cfset mac.init(key) /><br /> <cfset mac.update(jMsg) /><br /><br /> <cfreturn mac.doFinal() /><br /><br /></cffunction><br /></pre>
<p><strong>oauth_base_string()</strong>: Generates the OAuth "base string" from
the parameters of your OAuth request. Technically speaking, this code
belongs inside the <em>oauth_request() </em>function, described next, being that the <em>oauth_base_string() </em>code isn't reused anywhere. However, for the purposes of debugging, I chose to break this pesky little step out. And, for the purposes of education and clarity, I've left things this way. For example, it does become clearer from this function why oauth parameters are twice URL-encoded in a signature base string.</p>
<pre><!--- ************************************************************ ---><br /><!--- OAUTH SIGNATURE BASE STRING FUNCTION ---><br /><!--- ---><br /><!--- In accordance with the OAuth specification, this function ---><br /><!--- takes three input values (http method, base uri, and a ---><br /><!--- list, er, 'structure' of "key = value" parameters) and ---><br /><!--- returns a single OAuth base string. ---><br /><!--- ---><br /><!--- AUTHOR ---><br /><!--- Dave Delbridge, Circa 3000 (http://circa3000.com) ---><br /><!--- ---><br /><!--- PARAMETERS ---><br /><!--- HTTP_METHOD (string) = "GET" or "POST" ---><br /><!--- BASE_URI (string) = address where request will be sent, ---><br /><!--- minus any URL request parameters ---><br /><!--- PARAMETERS (structure) = key/value parameter pairs ---><br /><!--- Example: ---><br /><!--- params[oauth_nonce] = 12345 ---><br /><!--- params[oauth_version] = "1.0" ---><br /><!--- ---><br /><!--- RETURNS ---><br /><!--- (string) The sorted, URL-encoded, concatenated values ---><br /><!--- (the "signature base string") per OAuth spec ---><br /><!--- ---><br /><!--- ************************************************************ ---><br /><br /><cffunction name="OauthBaseString" returntype="string" access="public" output="no"><br /><br /> <!--- ************************************************************ ---><br /> <!--- Required parameters (http_method, base_uri, values) ---><br /> <!--- ************************************************************ ---><br /><br /> <cfargument name="http_method" type="string" required="true"><br /> <cfargument name="base_uri" type="string" required="true"><br /> <cfargument name="parameters" type="struct" required="true"><br /><br /> <!--- ************************************************************ ---><br /> <!--- Concatenate http_method & URL-encoded base_uri ---><br /> <!--- ************************************************************ ---><br /><br /> <cfset oauth_signature_base_string = http_method & "&" & URLEncodedFormat_3986(base_uri) & "&"><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Create sorted list of parameter keys ---><br /> <!--- ************************************************************ ---><br /><br /> <cfset keys_list = StructKeyList(parameters)><br /> <cfset keys_list_sorted = ListSort(keys_list,"textnocase")><br /> <br /> <cfset amp = ""> <!--- first iteration requires no ampersand ---><br /><br /> <!--- ************************************************************ ---><br /> <!--- Repeat for each parameter ---><br /> <!--- ************************************************************ ---><br /><br /> <cfloop list="#keys_list_sorted#" index="key"><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Concatenate URL-encoded parameter (key/value pair) ---><br /> <!--- ************************************************************ ---><br /><br /> <cfset oauth_signature_base_string = oauth_signature_base_string & URLEncodedFormat_3986(amp & LCase(key) & "=" & parameters[key])><br /><br /> <cfset amp = "&"> <!--- successive iterations require a starting ampersand ---><br /> <br /> </cfloop><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Return with OAuth signature base string ---><br /> <!--- ************************************************************ ---><br /><br /> <cfreturn oauth_signature_base_string><br /> <br /></cffunction><br /></pre>
<p><strong>oauth_request()</strong>: This is the engine of the OAuth car.
Generates the OAuth request header and signature, submits to the
provider (e.g., Twitter) and returns the response in a string.</p>
<p><em>For the record, this template was updated on 10/03/2011, responding to comments that URL request parameter values containing ampersand (&) and equals (=) symbols created trouble. To further complicate things, Twitter has since updated their instructions - they no longer recommend passing URL query parameters in what amounts to a malformed URL. This is understandable, being that parsing name/value pairs from an unencoded, malformed URL is, well, really not possible. Rather than rewrite this article to keep pace with their new JSON examples, my workaround is to simply allow for </em><em>escaped symbols (e.g., "&&", "==") in the URL request parameter </em><em>values. Be sure to escape those values before passing them to these templates, or you will generate an error.</em></p>
<pre><!--- ************************************************************ ---><br /><!--- OAUTH REQUEST FUNCTION ---><br /><!--- ---><br /><!--- Per OAuth specification, sends specified request and ---><br /><!--- parameters to the specified provider (e.g., Twitter). ---><br /><!--- Response is returned in a string. ---><br /><!--- ---><br /><!--- AUTHOR ---><br /><!--- Dave Delbridge, Circa 3000 (http://circa3000.com) ---><br /><!--- ---><br /><!--- PARAMETERS ---><br /><!--- HTTP_METHOD (string) = "GET" or "POST" ---><br /><!--- REQUEST_URL (string) = unencoded address where request is ---><br /><!--- to be sent, including any URL request parameters. All ---><br /><!--- ampersand (&) and equals (=) symbols appearing in any ---><br /><!--- URL request parameter values must be escaped (e.g., ---><br /><!--- "&&", "=="). ---><br /><!--- OAUTH_CONSUMER_SECRET (string) = consumer secret provided ---><br /><!--- by provider (e.g., Twitter) ---><br /><!--- PARAMS = structure containing request parameters ---><br /><!--- Example: ---><br /><!--- params[oauth_nonce] = 12345 ---><br /><!--- params[oauth_version] = "1.0" ---><br /><!--- ---><br /><!--- RETURNS ---><br /><!--- (string) The provider's response ---><br /><!--- ---><br /><!--- ************************************************************ ---><br /><br /><cffunction name="oauth_request" returntype="string" access="public" output="no"><br /><br /> <!--- ************************************************************ ---><br /> <!--- Parameters ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfargument name="consumer_secret" type="string" required="yes"><br /> <cfargument name="token_secret" type="string" required="yes"><br /> <cfargument name="http_method" type="string" required="yes"><br /> <cfargument name="request_url" type="string" required="yes"><br /> <cfargument name="params" type="struct" required="yes"><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Load necessary functions ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfinclude template = "../_functions/urlencodedformat_3986.cfm"><br /> <cfinclude template = "../_functions/oauth_base_string.cfm"><br /> <cfinclude template = "../_functions/hmac_sha1.cfm"><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Backup parameters for later ---><br /> <!--- ************************************************************ ---><br /><br /> <cfset params_backup = Duplicate(params)><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Copy URL variables (if any) to parameters ---><br /> <!--- ************************************************************ ---><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Parse address and parameters from request URL ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset request_url_address = request_url><br /> <cfset request_url_query_string = ""><br /> <br /> <cfset question_mark = Find("?",request_url,1)><br /> <br /> <cfif question_mark neq 0><br /> <br /> <cfset request_url_address = Left(request_url,question_mark-1)><br /> <cfset request_url_query_string = Right(request_url,(len(request_url)-question_mark))><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Repeat for each key/value pair ---><br /> <!--- ************************************************************ ---><br /><br /> <cfset request_url_query_string = Replace(request_url_query_string, "&&", "PLACEHOLDER_AMPERSAND", "ALL")> <!--- save escaped ampersand (&) symbols ---><br /> <cfset request_url_query_string = Replace(request_url_query_string, "==", "PLACEHOLDER_EQUALS", "ALL")> <!--- save escaped equals (=) symbols ---><br /><br /> <cfset params_list = ListChangeDelims(request_url_query_string,",","&,=")><br /> <br /> <cfloop from="1" to="#ListLen(params_list)#" index="index" step="2"><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Add parameter to Params structure ---><br /> <!--- ************************************************************ ---><br /><br /> <cfset params[ListGetAt(params_list,index)] = ListGetAt(params_list,index+1)><br /> <br /> <cfset params[ListGetAt(params_list,index)] = Replace(params[ListGetAt(params_list,index)], "PLACEHOLDER_AMPERSAND", "&", "ALL")> <!--- restore escaped ampersand (&) symbols as non-escaped ---><br /> <cfset params[ListGetAt(params_list,index)] = Replace(params[ListGetAt(params_list,index)], "PLACEHOLDER_EQUALS", "=", "ALL")> <!--- restore escaped equals (=) symbols as non-escaped ---><br /><br /> </cfloop><br /> <br /> </cfif><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Generate signature base string ---><br /> <!--- ************************************************************ ---><br /> <br /> <!--- ************************************************************ ---><br /> <!--- All parameters must be URL-encoded ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfloop list="#StructKeyList(params)#" index="key"><br /> <br /> <cfset params[key] = URLEncodedFormat_3986(params[key])><br /> <br /> </cfloop><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Get the base string ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset signature_base_string = OauthBaseString(http_method,request_url_address,params)><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Generate composite signing key ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset composite_signing_key = consumer_secret & "&" & token_secret><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Generate the SHA1 hash ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset signature = ToBase64(HMAC_SHA1(composite_signing_key,signature_base_string))><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Hash (now that we have it) must also be URL encoded ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset signature = URLEncodedFormat_3986(signature)><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Submit request to provider (e.g., Twitter) ---><br /> <!--- ************************************************************ ---><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Generate header parameters string ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset oauth_header = "OAuth "><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Parameters (minus URL parameters) ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset comma = ""><br /> <br /> <cfloop list="#StructKeyList(params_backup)#" index="key"> <!--- use backup list of parameter keys to remove query parameters ---><br /> <br /> <cfset oauth_header = oauth_header & comma & key & "=""" & params[key] & """"> <!--- ...but use current (URL-encoded) parameter values ---><br /> <br /> <cfset comma = ", "><br /> <br /> </cfloop><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Signature ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset oauth_header = oauth_header & ", oauth_signature=""" & signature & """"><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Send request ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfhttp method="post" url="#request_url_address#"><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Header ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfhttpparam type="header" name="Authorization" value="#oauth_header#" encoded="no"><br /><br /> <!--- ************************************************************ ---><br /> <!--- Parameters ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfloop list="#StructKeyList(params)#" index="key"><br /><br /> <cfif not StructKeyExists(params_backup,key)> <!--- just the query parameters ---><br /> <br /> <cfhttpparam type="formfield" name="#key#" value="#params[key]#" encoded="no"><br /> <br /> </cfif><br /> <br /> </cfloop><br /><br /> </cfhttp><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Success? ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfif cfhttp.Statuscode neq "200 OK"><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Failure ---><br /> <!--- ************************************************************ ---><br /> <br /> <h1>Failure!</h1><br /> <br /> <cfdump var="#variables#"><br /> <br /> <cfabort><br /> <br /> </cfif><br /> <br /> <cfreturn cfhttp.FileContent><br /><br /></cffunction><br /></pre>
<p><strong>urlencodedformat_3986()</strong>: Enhances ColdFusion's URLEncoded() function to produce strings compliant with RFC 3986.</p>
<pre><!--- ************************************************************ ---><br /><!--- RFC 3986-COMPLIANT URLENCODEDFORMAT() FUNCTION ---><br /><!--- ---><br /><!--- Per "URL Encoding to RFC 3986" in Adobe's Developer ---><br /><!--- Connection, this function corrects inconsistencies in ---><br /><!--- ColdFusion's URLEncodedFormat() function that are known ---><br /><!--- to break OAuth authentication attempts. ---><br /><!--- ---><br /><!--- AUTHOR ---><br /><!--- Dave Delbridge, Circa 3000 (http://circa3000.com) ---><br /><!--- ---><br /><!--- PARAMETERS ---><br /><!--- URL (string) = address to be url-encoded ---><br /><!--- ---><br /><!--- RETURNS ---><br /><!--- (string) Url-encoded address, per RFC 3986 ---><br /><!--- ---><br /><!--- ************************************************************ ---><br /><br /><!--- ************************************************************ ---><br /><!--- Perform URL encoding and correct mistakes ---><br /><!--- ************************************************************ ---><br /><br /><cffunction name="URLEncodedFormat_3986" returntype="string" access="public" output="no"><br /><br /> <cfargument name="url" type="string" required="true" /><br /><br /> <cfset rfc_3986_bad_chars = "%2D,%2E,%5F,%7E"><br /> <cfset rfc_3986_good_chars = "-,.,_,~"><br /><br /> <cfset url = ReplaceList(URLEncodedFormat(url),rfc_3986_bad_chars,rfc_3986_good_chars)><br /> <br /> <cfreturn url /><br /><br /></cffunction><br /></pre>
<h3>The Templates<br /></h3>
<p>This project also employs three templates. Copy the templates into the same directory that holds your "<em>_functions</em>" subdirectory, introduced above.</p>
<p>The first template
obtains a Request Token from Twitter and forwards the user to Twitter
for authentication. The second template, or "callback page," receives
the user back from Twitter, obtains an Access Token for the user and
stores it for future use, as you would a username and password with
Basic Authentication. In the third template, we send an API call to
Twitter, along with the Access Token.</p>
<p>For each of these templates, you must supply your own Consumer Key,
Consumer Secret (collectively, your "Consumer Token") and Callback URL
(your location for template <em>get_access_token.cfm</em>). In a perfect
world, Twitter would provide a public Consumer Token for testing
purposes, but alas, this is not the case. You'll need to go it alone - <em>that is, I
can't tell you what your results should look like</em> - and if things go
wrong, use the aforementioned validators to locate any trouble in your
base strings and request headers.</p>
<p><strong>get_request_token.cfm</strong>: As already explained, this is the first of two templates used to obtain an access token and fulfills steps A, B and C of <a href="http://a0.twimg.com/images/dev/oauth_diagram.png" target="_blank">Twitter's OAuth authentication flow diagram</a>.</p>
<pre><!--- ************************************************************ ---><br /><!--- GET OAUTH REQUEST TOKEN ---><br /><!--- ---><br /><!--- Executes the first three steps of Twitter's OAuth dia- ---><br /><!--- gram - sends Consumer Key to Twitter (Step A), receives ---><br /><!--- a Request Token (Step B), and redirects the user to ---><br /><!--- Twitter for authentication (Step C). ---><br /><!--- ---><br /><!--- Once authenticated, Twitter will return the user to us, ---><br /><!--- to the callback template specified here, in parameter ---><br /><!--- OAUTH_CALLBACK. Our callback url employs CF session ---><br /><!--- tokens to preserve session state (with our new request ---><br /><!--- tokens); no cookies required. ---><br /><!--- ---><br /><!--- AUTHOR ---><br /><!--- Dave Delbridge, Circa 3000 (http://circa3000.com) ---><br /><!--- ---><br /><!--- INPUT ---><br /><!--- n/a ---><br /><!--- ---><br /><!--- OUTPUT ---><br /><!--- SESSION.OAUTH_REQUEST_TOKEN = OAuth request token ---><br /><!--- SESSION.OAUTH_REQUEST_TOKEN_SECRET = OAuth request token ---><br /><!--- secret ---><br /><!--- ---><br /><!--- ************************************************************ ---><br /><br /><!--- ************************************************************ ---><br /><!--- Preserve session state ---><br /><!--- ************************************************************ ---><br /><br /><cfapplication sessionmanagement="yes" name="oauth" sessiontimeout="10"><br /><br /><!--- ************************************************************ ---><br /><!--- Load necessary functions ---><br /><!--- ************************************************************ ---><br /><br /><cfinclude template = "_functions/oauth_request.cfm"><br /><br /><!--- ************************************************************ ---><br /><!--- Variables ---><br /><!--- ************************************************************ ---><br /><br /><cfset gmt_time_zone = "8"> <!--- Greenwich mean time offset at server ---><br /><br /><cfset http_method = "POST"><br /><cfset request_url = "http://twitter.com/oauth/request_token"><br /><cfset oauth_consumer_secret = "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98"><br /><br /><cfset params = StructNew()><br /><br /><cfset params["oauth_callback"] = "http://www.mysite.com/twitter/oauth/get_access_token.cfm?#session.URLToken#"><br /><cfset params["oauth_consumer_key"] = "<span class="description">GDdmIQH6jhtmLUypg82g</span>"><br /><cfset params["oauth_nonce"] = DateFormat(Now(),'yymmdd') & TimeFormat (Now(),'hhmmssl')><br /><cfset params["oauth_signature_method"] = "HMAC-SHA1"><br /><cfset params["oauth_timestamp"] = DateDiff("s", "January 1 1970 00:00", (Now()+(gmt_time_zone/24)))><br /><cfset params["oauth_version"] = "1.0"><br /><br /><!--- ************************************************************ ---><br /><!--- Submit OAuth request ---><br /><!--- ************************************************************ ---><br /><br /><cfset oauth_response = oauth_request(oauth_consumer_secret,"",http_method,request_url,params)><br /><br /><!--- ************************************************************ ---><br /><!--- Parse and store the results ---><br /><!--- ************************************************************ ---><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Request Token (variable-length) ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset oauth_token_start = Find("oauth_token=",oauth_response)+12><br /> <cfset oauth_token_end = Find("&",oauth_response,oauth_token_start)><br /> <cfset session.oauth_request_token = Mid(oauth_response,oauth_token_start,(oauth_token_end-oauth_token_start))><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Request Token secret (variable-length) ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset oauth_token_secret_start = Find("oauth_token_secret=",oauth_response)+19><br /> <cfset oauth_token_secret_end = Find("&",oauth_response,oauth_token_secret_start)><br /> <cfset session.oauth_request_token_secret = Mid(oauth_response,oauth_token_secret_start,(oauth_token_secret_end-oauth_token_secret_start))><br /><br /> <!--- ************************************************************ ---><br /> <!--- Callback confirmation flag (true/false) ---><br /> <!--- ************************************************************ ---><br /><br /> <!--- ignored ---><br /> <br /><!--- ************************************************************ ---><br /><!--- Forward user to Twitter for authentication ---><br /><!--- ************************************************************ ---><br /><br /><cflocation url="https://api.twitter.com/oauth/authorize?oauth_token=#session.oauth_request_token#"><br /></pre>
<p><strong>get_access_token.cfm</strong>: Our "callback page," users are sent
here after successful authentication at TWITTER.COM (Step D). Next, we
obtain an Access Token from Twitter (Steps E and F) and store the token
for future use.</p>
<pre><!--- ************************************************************ ---><br /><!--- OAUTH CALLBACK PAGE / GET OAUTH ACCESS TOKEN ---><br /><!--- ---><br /><!--- Fourth, fifth and sixth steps of OAuth procedure (in ---><br /><!--- Twitter's OAuth diagram). This is our "callback" page, ---><br /><!--- where the provider (e.g., Twitter) forwards users upon ---><br /><!--- successful authentication, along with a new verification ---><br /><!--- token (Step D). ---><br /><!--- ---><br /><!--- Next, the verification token is sent to the provider ---><br /><!--- (Step E) in exchange for an Access Token (Step F). This ---><br /><!--- is the final authentication request. Store the Access ---><br /><!--- Token in a database, for example, as you would a username ---><br /><!--- and password under Basic Authentication. ---><br /><!--- ---><br /><!--- AUTHOR ---><br /><!--- Dave Delbridge, Circa 3000 (http://circa3000.com) ---><br /><!--- ---><br /><!--- INPUT ---><br /><!--- URL.OAUTH_TOKEN = copy of Request Token, sent from ---><br /><!--- Twitter, should match session.oauth_token ---><br /><!--- URL.OAUTH_VERIFIER = verifier sent from Twitter ---><br /><!--- URL.CFID = CF session state var specified in Callback URL ---><br /><!--- URL.CFTOKEN = ditto ---><br /><!--- SESSION.OAUTH_REQUEST_TOKEN = Request Token received in ---><br /><!--- Step B ---><br /><!--- SESSION.OAUTH_REQUEST_TOKEN_SECRET = Request Token Secret ---><br /><!--- from Step B ---><br /><!--- ---><br /><!--- OUTPUT ---><br /><!--- OAUTH_ACCESS_TOKEN = access token returned from provider ---><br /><!--- OAUTH_ACCESS_TOKEN_SECRET = key returned from provider ---><br /><!--- ---><br /><!--- ************************************************************ ---><br /><br /><br /><!--- ************************************************************ ---><br /><!--- Recover session state from url ---><br /><!--- ************************************************************ ---><br /><br /><cfapplication sessionmanagement="yes" name="oauth" sessiontimeout="10"><br /><br /><!--- ************************************************************ ---><br /><!--- Load necessary functions ---><br /><!--- ************************************************************ ---><br /><br /><cfinclude template = "_functions/oauth_request.cfm"><br /><br /><!--- ************************************************************ ---><br /><!--- Variables ---><br /><!--- ************************************************************ ---><br /><br /><cfset gmt_time_zone = "8"> <!--- Greenwich mean time offset at server ---><br /><br /><cfset http_method = "POST"><br /><cfset request_url = "http://api.twitter.com/oauth/access_token"><br /><cfset oauth_consumer_secret = "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98"><br /><br /><cfset params = StructNew()><br /><br /><cfset params["oauth_consumer_key"] = "GDdmIQH6jhtmLUypg82g"><br /><cfset params["oauth_nonce"] = DateFormat(Now(),'yymmdd') & TimeFormat (Now(),'hhmmssl')><br /><cfset params["oauth_signature_method"] = "HMAC-SHA1"><br /><cfset params["oauth_token"] = url.oauth_token><br /><cfset params["oauth_timestamp"] = DateDiff("s", "January 1 1970 00:00", (Now()+(gmt_time_zone/24)))><br /><cfset params["oauth_verifier"] = url.oauth_verifier><br /><cfset params["oauth_version"] = "1.0"><br /><br /><!--- ************************************************************ ---><br /><!--- Submit OAuth request ---><br /><!--- ************************************************************ ---><br /><br /><cfset oauth_response = oauth_request(oauth_consumer_secret,session.oauth_request_token_secret,http_method,request_url,params)><br /><br /><!--- ************************************************************ ---><br /><!--- Parse and store the results ---><br /><!--- ************************************************************ ---><br /><br /> <!--- ************************************************************ ---><br /> <!--- Get token (variable-length) ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset oauth_token_start = Find("oauth_token=",oauth_response)+12><br /> <cfset oauth_token_end = Find("&",oauth_response,oauth_token_start)><br /> <cfset oauth_access_token = Mid(oauth_response,oauth_token_start,(oauth_token_end-oauth_token_start))><br /> <br /> <!--- ************************************************************ ---><br /> <!--- Get token secret (variable-length) ---><br /> <!--- ************************************************************ ---><br /> <br /> <cfset oauth_token_secret_start = Find("oauth_token_secret=",oauth_response)+19><br /> <cfset oauth_token_secret_end = Find("&",oauth_response,oauth_token_secret_start)><br /> <cfset oauth_access_token_secret = Mid(oauth_response,oauth_token_secret_start,(oauth_token_secret_end-oauth_token_secret_start))><br /> <br /><!--- ************************************************************ ---><br /><!--- Now that we have our access token, store it in a database ---><br /><!--- as you would a username and password under Basic Authenti- ---><br /><!--- cation. [For educational purposes, we will instead display ---><br /><!--- the Access Token with some instructions.] ---><br /><!--- ************************************************************ ---><br /><br /><cfoutput><br /><br /> <p><br /> Access Token: #oauth_access_token#<br /><br /> Access Token Secret: #oauth_access_token_secret#<br /> </p><br /><br /> <p>Normally, you would now store these in a database, as you would a username and password under Basic Authentication. For the purposes of instruction, we will instead pass these variables to the final template, CALL_METHOD.CFM, in URL variables. To proceed, click this link: <a href="call_method.cfm?oauth_token=#oauth_access_token#&oauth_token_secret=#oauth_access_token_secret#">call_method.cfm?oauth_token=#oauth_access_token#&oauth_token_secret=#oauth_access_token_secret#</a></p><br /> <br /></cfoutput><br /></pre>
<p><strong>call_method.cfm</strong>: With our Access Token in hand, we can finally submit a Twitter API call. Or two. Or three...</p>
<pre><!--- ************************************************************ ---><br /><!--- ACCESS PROTECTED RESOURCES ---><br /><!--- ---><br /><!--- The final step of OAuth procedure (Step G), submits a ---><br /><!--- specified Twitter API call against a protected resource. ---><br /><!--- The target account must match the specified Access Token ---><br /><!--- (OAUTH_TOKEN and OAUTH_TOKEN_SECRET). ---><br /><!--- ---><br /><!--- AUTHOR ---><br /><!--- Dave Delbridge, Circa 3000 (http://circa3000.com) ---><br /><!--- ---><br /><!--- INPUT ---><br /><!--- URL.OAUTH_TOKEN = Access Token given to us in Step F ---><br /><!--- URL.OAUTH_TOKEN_SECRET = Access Token secret given to us ---><br /><!--- in Step F ---><br /><!--- ---><br /><!--- OUTPUT ---><br /><!--- OAUTH_RESPONSE = provider's response ---><br /><!--- ---><br /><!--- ************************************************************ ---><br /><br /><!--- ************************************************************ ---><br /><!--- Make sure international characters are encoded properly ---><br /><!--- ************************************************************ ---><br /><br /><cfprocessingdirective pageEncoding="utf-8"><br /><br /><!--- ************************************************************ ---><br /><!--- Load necessary functions ---><br /><!--- ************************************************************ ---><br /><br /><cfinclude template = "_functions/oauth_request.cfm"><br /><br /><!--- ************************************************************ ---><br /><!--- Variables ---><br /><!--- ************************************************************ ---><br /><br /><cfset gmt_time_zone = "8"> <!--- Greenwich mean time offset at server ---><br /><br /><cfset http_method = "POST"><br /><cfset request_url = "http://api.twitter.com/1/statuses/update.xml?status=yet another test of my new twitter account 私のさえずりを設定する"><br /><cfset oauth_consumer_secret = "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98"><br /><br /><cfset params = StructNew()><br /><br /><cfset params["oauth_consumer_key"] = "<span class="description">GDdmIQH6jhtmLUypg82g</span>"><br /><cfset params["oauth_nonce"] = DateFormat(Now(),'yymmdd') & TimeFormat (Now(),'hhmmssl')><br /><cfset params["oauth_signature_method"] = "HMAC-SHA1"><br /><cfset params["oauth_token"] = url.oauth_token><br /><cfset params["oauth_timestamp"] = DateDiff("s", "January 1 1970 00:00", (Now()+(gmt_time_zone/24)))><br /><cfset params["oauth_version"] = "1.0"><br /><br /><!--- ************************************************************ ---><br /><!--- Submit OAuth request ---><br /><!--- ************************************************************ ---><br /><br /><cfset oauth_response = oauth_request(oauth_consumer_secret,url.oauth_token_secret,http_method,request_url,params)><br /><br /><!--- ************************************************************ ---><br /><!--- Display the results ---><br /><!--- ************************************************************ ---><br /><br /><cfoutput><br /><br /> <h1>Twitter's Response</h1><br /> <br /> <p>#HTMLCodeFormat(oauth_response)#</p> <br /> <br /></cfoutput><br /></pre>
<h3>The Path Ahead<br /></h3>
<p>Now, all that's left to do is upgrade your own Twitter apps from
Basic Authentication. Using the first two templates as a guide, update
your applications' login pages, storing the Access Tokens in place of
username and password. Then, using the <em>call_method.cfm </em>template as a guide, perhaps create a general-purpose <em>twitter()</em> function, or maybe individual functions for those secured Twitter API methods you use most (e.g., <em>update_status()</em>, <em>follow_id()</em>). Have fun!</p>
<p>I hope this has been helpful. If so, you can follow me on Twitter at <a href="http://twitter.com/circa3000" target="_blank">@circa3000</a>. And, of course, please consider <a href="http://www.circa3000.com/" target="_blank">Circa 3000</a> for your ColdFusion hosting needs. I look forward to hearing from you!</p>
A Musician's Guide to QR Code
urn:uuid:65CE81F7-7E98-2630-CC5FD06153E03BD4
2010-06-25T05:06:00Z
2010-06-27T02:06:00Z
<p><img style="margin-left: 20px; margin-right: 20px; float: right;" src="http://blog.delbridge.org/assets/content//qr-code-rigel7.gif" alt="QR Code" width="150" height="150" />For DIY musicians, Quick Response Code, or "QR Code," may represent the
biggest thing to hit guerilla music marketing since the vuvuzela. And
by "hit," I mean a right sucker punch to the mouth. Already the rage in
Japan, passers-by can scan a band's gig poster into their smartphone
and download a free music sample on the spot, or be transported to a
special web page with discounted ticket and merchandise offers.</p>
<p>But elsewhere - <em>I'm looking at you, America</em> - QR Code is only
just catching on. And that's good news for ambitious bands looking to capitalize on emerging
trends. Bleeding edge, be damned! Let's put these codes to work for us
now, while the novelty is hot and before the competition catches up.</p>
Dave Delbridge
<p style="text-align: left;"><img style="float: right; margin-left: 20px; margin-right: 20px;" src="http://blog.delbridge.org/assets/content//qr-code-rigel7.gif" alt="QR Code" width="150" height="150" />For DIY musicians, Quick Response Code, or "QR Code," may represent the biggest thing to hit guerilla music marketing since the vuvuzela. And by "hit," I mean a right sucker punch to the mouth. Already the rage in Japan, passers-by can scan a band's gig poster into their smartphone and download a free music sample on the spot, or be transported to a special web page with discounted ticket and merchandise offers. Engaging stuff.</p>
<p style="text-align: left;">But elsewhere - <em>I'm looking at you, America</em> - QR Code is only just catching on. Many camera-equipped smart phones still cannot scan the curious pictograms with any reliability. Those that do may fail to launch the phone's native web browser or refuse to download an MP3 audio file. Welcome to the bleeding edge. What's more, American consumers are only just becoming familiar with the crossword-like squares and how they can open gateways to free music and discounted goodies.</p>
<p style="text-align: left;">But wait! That's good news for ambitious bands looking to capitalize on emerging trends. Bleeding edge, be damned! Let's put these codes to work for us now, while the novelty is hot and before the competition catches up.</p>
<h3 style="text-align: left;">What Is QR Code?</h3>
<p style="text-align: left;">Technically speaking, QR Code is an improved, two-dimensional bar code. Whereas traditional barcodes provide one line of information with limited error correction <em>- this is evidenced by the number of times your checkout clerk scans and rescans your deli meat -</em> QR Codes provide multiple lines of information and much greater error correction. In fact, with as much as 30% of a QR code smudged or missing, a quality scanner can still read and interpret the code's meaning. Try <em>that </em>with your meat.</p>
<table style="padding: 20px;" border="0" cellspacing="0" width="220" align="right">
<tbody>
<tr style="background-color: #dbdadb;">
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">QR Code Error Correction Levels</td>
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">Capability</td>
</tr>
<tr>
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">Level
L</td>
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">~ 7%</td>
</tr>
<tr>
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">Level
M</td>
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">~ 15%</td>
</tr>
<tr>
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">Level
Q</td>
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">~ 25%</td>
</tr>
<tr style="border-bottom: 1pt solid #777777;">
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">Level
H</td>
<td style="border-left-width: 1px; border-left-style: solid; border-top-width: 1px; border-top-style: solid; margin: 5pt;" align="center">~ 30%</td>
</tr>
</tbody>
</table>
<p style="text-align: left;">To be specific, the QR Code technical specification defines four selectable levels of error correction<em> (see table)</em>, employing the same Reed-Solomon error correction algorithm used by music CDs. Greater levels of error correction capability require more data redundancy and, consequently, will increase the size ("symbol version") of the symbol accordingly.</p>
<p style="text-align: left;">QR Code is free to use. Japanese corporation, Denso-Wave, invented the technology in 1994, but chose to share, rather than capitalize on its patents.</p>
<p style="text-align: left;">Though designed for commercial parts and shipment tracking, QR Code has become synonymous with mobile tagging, or hardlinking, whereby physical objects are linked to virtual content. When printed in a magazine ad or on a billboard, for example, consumers may scan the real-world advertisements with a camera-equipped smart phone and immediately view the linked virtual content.</p>
<p style="text-align: left;">To that end, mobile tagging appears to be purpose-built for musicians. How many industries market a product that can be beamed freely to its customers? Just as the Internet and MP3 file formats equalized music <em>distribution </em>in the 90's, mobile tagging takes an equivalent leap forward in the field of music <em>marketing</em>. Other businesses can deliver offers and incentives, but only media makers can deliver the goods. Anywhere. On the spot.</p>
<p style="text-align: left;">It's also worth noting that indies and DIY musicians who already offer free music downloads can make the most of QR Code right away, while traditional record labels continue their struggle with digital music, downloads, and generally, the 21st century. In other words, those who give the most can gain the most from QR Code.</p>
<h3 style="text-align: left;">How To Make Your Own QR Code</h3>
<p style="text-align: left;">The Internet is chok full o' free QR Code applications you can use to create your own code images. My personal favorite is Kerem Erkan's <a href="http://keremerkan.net/qr-code-and-2d-code-generator/" target="_blank">QR Code and 2D Code Generator</a> <em>(http://keremerkan.net/qr-code-and-2d-code-generator/)</em>, by virtue of its features. Of the code generators I tested, some were prettier, but Kerem's was the only one that allowed for the selection of error correction level.</p>
<p style="text-align: left;">Another QR Code generator worth checking out is offered by <a href="http://www.i-nigma.com/CreateBarcodes.html" target="_blank">i-nigma.com</a> (http://www.i-nigma.com/CreateBarcodes.html). Though fixed at Level M error correction, it displays and updates your QR Code image in real-time, as you type. This novelty demonstrates nicely the relationship between coded message size and code version <em>(image complexity)</em>.</p>
<p style="text-align: left;">Not enough online code generators fer ya? Check out the list of <a href="http://2d-code.co.uk/qr-code-generators/" target="_blank">QR Code Generators Online</a>, at 2D Code.</p>
<h3 style="text-align: left;">WhERE Should My QR Codes Link To?<br /></h3>
<p style="text-align: left;">When choosing a link destination, consider the longevity of the marketing campaign. Shorter and experimental campaigns pose few concerns. However, if you'll tattoo your code on your forehead <em>(see "Where To Display Your QR Code," below) </em>or otherwise publish your code forever and ever, it's critical that you maintain 100% control of the destination content. Do not link to Facebook, Twitter, MySpace, YouTube or any other third-party destination because, quite simply, they might not be popular, accessible or alive in ten years. Instead, be sure to link to a domain name that you own, that is free from any potential trademark, business or partnership conflicts and that holds content you can readily modify at any time - that is to say, the content is not built upon a particular programming language or other technology that will limit your options.</p>
<p style="text-align: left;">Long-term campaigns should probably link to a standard HTML web page rather than a music, movie or other media file <em>(e.g., http://mywebsite.com/mymusic.mp3)</em>. While you might be able to replace the <em>"mymusic.mp3"</em> content, you will be limited to that file format and, again, the format might be incompatible with future media players. By contrast, a standard web page is largely future-proof and can either incorporate, link to or automatically redirect visitors to your content du jour, including said MP3 audio file.</p>
<p style="text-align: left;">To further protect yourself from digital obsolescence, I recommend using a directory URL <em>(e.g., http://mywebsite.com/mysub/)</em> rather than a document URL <em>(e.g., http://mywebsite.com/mysub/index.html)</em>. This way, you can specify the default filename to deliver in the web server's settings and, more importantly, change it later. So, for example, your web server could deliver a default document of <em>index.html </em>today, <em>index.php </em>tomorrow <em>(when you launch that new interactive webpage design)</em>, <em>mysong.mp3 </em>next month, and <em>mysong.mp6 </em>when the audio file format is invented in ten years.</p>
<p style="text-align: left;">A directory URL also has the advantage of being shorter. Shorter URLs in your QR Codes have two benefits. First, if you choose to display the unencoded URLs aside your QR Code pictograms <em>(many advertisers do this for the benefit of those without a compatible phone)</em>, shorter URLs are easier to remember and much easier to type into a Blackberry or other "thumby" device. Another advantage of short URLs is that they produce smaller, simpler QR Code images that are easier to scan at small sizes and greater distances. When embroidered on a hat, for example, the code image produced by a lengthy URL may be too complex for sewing machines to render properly and the results too choppy for scanners to read.</p>
<p style="text-align: left;">To demonstrate the importance of small webpage address URLs, the three QR Code blocks displayed below resolve to addresses with twenty-nine characters, 60 characters, and 90 characters, respectively. Which one would you feel safest stitching on your band's 2010 world tour apparel?</p>
<p style="text-align: left;"><img src="http://blog.delbridge.org/assets/content//qr-code-versions.gif" alt="QR Code Versions" width="500" height="154" /></p>
<p style="text-align: left;">And while we are on the subject of image optimization, we should discuss error correction, being that higher correction levels produce larger, more complex code images. Fortunately, error correction Level L <em>(the lowest error correction level)</em> is sufficient for most print applications and affords the smallest, simplest code images. Anything above Level M is discouraged, except for mission-critical applications that are likely to generate damage to the code image, such as inventory tracking and shipping. That said, know that higher error correction levels afford greater artistic freedom, should you wish to incorporate overlapping graphics, non-uniform backgrounds and low-contrast colors, for example, into your design. Irregular surfaces, such as T-shirts might also demand Level M. But there's no one-size-fits-all rule here. Use your own judgement and, most importantly, test thoroughly before committing to a high-production run.</p>
<p style="text-align: left;">As already suggested, musicians will be tempted to link their QR Code directly to an MP3 audio file. However, my experiments revealed a few caveats. First, American cell phone technology isn't quite ready for this application. In my attempts with Blackberry and iPhone 3GS smart phones, only one out of four code reader applications succeeded in cueing up the destination audio file. Not surprisingly, the commercial ($0.99) QuickMark iPhone app <em>- it is recommended by Google - </em>succeeded while all of the free code readers failed.</p>
<p style="text-align: left;">Another thing to consider when linking to MP3 files is that many cell phones operate on limited data plans. As such, when you push a multi-megabyte file to somebody's phone without warning, it could be regarded as a frivolous, self-serving consumption of the subscriber's resources. While it remains to be seen how public opinion will judge such promotional activities, a safer alternative would be to offer an opt-in landing page instead. On it, you can clarify the song title, file size, and a bold "download now" button, linking to the opt-in MP3 file.</p>
<p style="text-align: left;">Have fun with
your links! Those who scan your code want to be surprised and
rewarded, so give them a gift - free music, free tickets, a discount, a
laugh, or some other surprise. Hold a contest or scavenger hunt,
incorporating QR codes pasted around town. Whatever you do, <em>do not</em>
punish your visitors with a heartless sales pitch. Deflate them and
they might not bother to scan your next poster. Or worse, they might not bother to scan <em>anybody's</em> poster.</p>
<h3 style="text-align: left;">Where To Display Your QR Code</h3>
<p style="text-align: left;">For guerilla music marketers, QR Code pops the top on a whole new can of opportunities. Anywhere you would display a promotional piece, you can hang or incorporate a custom QR Code. And if graphic design is your weak point, you can take advantage of QR Code's novelty right now by pasting unmodified printouts around town.</p>
<p style="text-align: left;">Give your QR Code legs! Branded T-shirts and hats have longevity over posters while adding a social component. Artists can wear their own codes and invite prospective fans to "scan me"<em> (wink, wink)</em>. And speaking of sex <em>- you knew I'd get there eventually - </em>silkscreen your code in a tantalizing spot<em> (e.g., butt shorts)</em> for laughs and flirtatious scans. How 'bout a tattoo? If that's too bold <em>(or too "big brother") </em>for you, know that custom temporary tattoos are also available and make terrific give-aways.</p>
<p>Nevermind that QR Codes will appear in national and international advertising campaigns. For indie bands, QR Code returns our attention to the local market, or wherever you have a street presence. In other words, the worldwide Internet, though heralded as the "great equalizer" for struggling musicians, has become a crowded, difficult environment in which to gain fans. But place a QR Code on your gig posters and watch your website buzz with new fans. What's more, you'll generate local fans who might otherwise never attend a live show.</p>
<p style="text-align: left;">Last, but certainly not least, be sure to create a separate QR Code for each of your advertising campaigns. Record the name and description of the campaign <em>(e.g., "Sacramento Gig Posters")</em>, the publication date and destination link <em>(e.g., http://myband.com/qrcode/sac_gig_2010/)</em>. This way, you can track the success of each campaign in Google's WebSense or other web stats application and tweak your promotional efforts accordingly.</p>
<p style="text-align: left;">That's it, my minions of self-construction. I sincerely hope you find this information helpful. Now, go perpetrate some mobile tagging and be quick about it, before I beat ya to it.</p>
Mouse Trouble in Microsoft Word After Windows Update
urn:uuid:B5661826-7E98-2630-CBFC357727D5FA64
2010-03-31T11:03:00Z
2010-03-31T11:03:00Z
<p>It must be Wednesday. My Windows desktop is blissfully clean where
three-hundred Firefox windows once were, and Microsoft Word 2007 has
gone funky - the mouse doesn't work, except for opening menus. Yup, it's Wednesday, when Microsoft pushes out its Windows updates. I've
seen this four times now and, though it has been documented elsewhere,
I'm composing this blog post - a note to myself, really - so that I
may never again need to Google the solution.</p>
Dave Delbridge
<p>It must be Wednesday. My Windows desktop is blissfully clean where three-hundred Firefox windows once were, and Microsoft Word 2007 has gone funky - the mouse doesn't work, except for opening menus. Yup, it's Wednesday, when Microsoft pushes out its Windows updates. I've seen this four times now and, though it has been documented elsewhere, I'm composing this blog post - a note to myself, really - so that I may never again need to Google the solution.</p>
<p>To clarify the problem, after a Windows Update, the mouse pointer in Microsoft Word 2007 refuses to select most application controls, including document components, window sliders, and more. Menu items will function, if only enough to close the application, but then Word throws an application failure message with the option to restart Word and to notify Microsoft of the trouble. When Word restarts, the problem recurs. Likewise, restarting the system doesn't remedy the situation.</p>
<p>The solution, it turns out, is to remove (or, more prudently, rename) a particular Windows registry key. Here's the steps:</p>
<ol>
<li>Close Microsoft Word 2007</li>
<li>Launch Windows Registry Editor (regedit.exe)</li>
<li>Rename the following registry key to "Data_Backup," for example:
<br /><br />
<blockquote>
<pre>HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Data</pre>
</blockquote>
</li>
<li>Close Registry Editor</li>
</ol>
<p>The trouble should be gone. Launch Microsoft Word 2007 and resume your document-editing goodness.</p>
<p>I hope you find this information helpful.</p>
How to Install ColdFusion 9 on Windows 2000 / IIS 5
urn:uuid:44458693-7E98-2630-C0AE020D9177FAB6
2010-03-06T11:03:00Z
2010-10-22T03:10:00Z
<p>With the release of Coldfusion 9, Adobe has
officially discontinued CF support for Windows 2000, this just prior to the
operating system's official EOL. However, while the workaround is tedious and officially "unsupported" by Adobe, I'm happy to report that ColdFusion 9 can indeed be installed on
Windows 2000 with IIS. For step-by-step instructions, read on....</p>
Dave Delbridge
<p>With the release of Coldfusion 9, Adobe has officially discontinued CF support for Windows 2000, this just prior to the operating system's official EOL. For what it's worth, it appears that the policy change was not by design. According to the blog post, "<a href="http://blog.pelcosolutions.com/2009/10/coldfusion-9-initial-reactions-installer-woes.html">Coldfusion 9 Initial Reactions: Installer Woes</a>," Adobe's official list of system requirements included Windows 2000 until problems were reported. Then, rather than produce a fix or publish a workaround in the Adobe Knowledgebase as would be typical, the company simply removed the OS from the list. This is evidenced by so many VARs still showing the original, uncorrected compatibility list. In another article (which I can't seem to locate), an Adobe support
rep offered suggestions for circumventing the installer, but with the caveat that any such installation, even if successful, would be "unsupported" by Adobe. That's scary if you plan to go live with CF9 on a Windows 2000 server. What might the next service pack do to your installation? But then, if you're reading this article, you're more scared by the expense of upgrading your OS and, no doubt, your "old-skool" server hardware. In this economy, non-essential upgrades are a luxury some of us simply can't afford.</p>
<p>I'm happy to report that ColdFusion 9 can indeed be installed on Windows 2000 with IIS. Success was the product of two separate Adobe TechNotes (and a little experience with prior CF versions):</p>
<ul>
<li><a href="http://kb2.adobe.com/cps/402/kb402572.html">Install ColdFusion 8 Silently</a></li>
<li><a href="http://kb2.adobe.com/cps/195/tn_19575.html">ColdFusion MX: Manually Configuring the Web Server Connector for ColdFusion MX Standalone</a></li>
</ul>
<p>Understand, however, that these TechNotes predate ColdFusion 9 and do not address this challenge directly. For clarity, I have parsed out the relevant bits and traced my exact steps below.</p>
<p>Needless to say, it is merely apparent at this time that my installation was successful - the ColdFusion Administrator has launched and no errors are apparent in any server logs or web pages. Still, there may yet be gremlins to discover. I will post any such discoveries here and encourage others to do the same. It's worth repeating that Adobe has declared installations of Coldfusion 9 on Windows 2000 to be "not supported." Likewise, I offer no guarantees. Proceed at your own risk.</p>
<h3>Part 1: ColdFusion 9 Command-Line Installation<br /></h3>
<p>Coldfusion 9's GUI installer fails on Windows 2000, getting itself stuck in a loop while trying to install the Microsoft VC++ 2008 Runtime. You can break out of this loop by closing the window, but then the installation fails nonetheless. The workaround is a command-line, or "silent" installation. Follow these steps to perform a silent Coldfusion 9 installation:</p>
<ol>
<li>With Notepad, create a new text file, with the following content. [For an explanation of these and other allowed parameters and acceptable values, visit the aforementioned Adobe TechNote, "<a href="http://kb2.adobe.com/cps/402/kb402572.html">Install ColdFusion 8 Silently</a>" and perhaps also "<a href="http://kb2.adobe.com/cps/000/87bd20f4.html">Installing ColdFusion MX 7 Silently</a>."] These are the values I used for installation on Windows 2000 w/ IIS 5.<br />
<br />
<pre>INSTALLER_UI=SILENT<br />SILENT_LICENSE_MODE=trial<br />SILENT_SERIAL_NUMBER=<br />SILENT_PREV_SERIAL_NUMBER=<br />SILENT_INSTALLER_TYPE=standalone<br />SILENT_INSTALL_ODBC=true<br />SILENT_INSTALL_VERITY=true<br />SILENT_INSTALL_SAMPLES=false<br />SILENT_INSTALL_JNBRIDGE=true<br />SILENT_INSTALL_FOLDER=C:\\ColdFusion9<br />SILENT_WEBROOT_FOLDER=C:\\Inetpub\\wwwroot<br />SILENT_ADMIN_PASSWORD=password<br />SILENT_ENABLE_RDS=false<br /></pre>
</li>
<li>Save the file as "CF.PROPERTIES" and close.</li>
<li>Copy the ColdFusion 9 installer (ColdFusion_9_WWE_win.exe) and CF.PROPERTIES file to C:\Temp.</li>
<li>From the Command Prompt, navigate to C:\Temp and launch the installer with the following command:
<br /><br />
<pre>COLDFUSION_9_WWE_WIN -f CF.PROPERTIES</pre>
</li>
<li>Give the installer plenty of time to finish. In silent mode, one might be tempted to restart the server before installation completes. If you'd like to verify that your installation was successfully completed, check out C:\Coldfusion9\Adobe_ColdFusion_9_InstallLog.log.</li>
</ol>
<h3>Part 2: Install ColdFusion 9's ISAPI Connector</h3>
<p>Having completed basic installation, we must now connect Coldfusion to IIS. Unfortunately, ColdFusion 9's Web Server Configuration Tool also does not work on Windows 2000. What's more, the command-line installer has not generated the necessary JRun files and directories necessary for manual configuration, making the next steps tedious, even if you're familiar with this exercise from prior versions of CF. Here goes:</p>
<ol>
<li>In Notepad, open C:\ColdFusion9\runtime\servers\coldfusion\SERVER-INF\jrun.xml.</li>
<li>Locate the entry labeled "ProxyService".</li>
<li>A few lines down, locate and modify the "deactivated" attribute to read "false," as follows. [Be careful - there are three separate instances of "deactivated" in this file. Make sure you modify the correct one.]
<br /><br />
<pre><attribute name="deactivated">false</attribute></pre>
</li>
<li>A few more lines down, locate and modify the "port" attribute to read "51800," as follows.
<br /><br />
<pre><attribute name="port">51800</attribute><br /></pre>
</li>
<li>Save and close the jrun.xml file.</li>
<li>Create the following directory:
<br /><br />
<pre>C:\ColdFusion9\runtime\lib\wsconfig\1</pre>
</li>
<li>With Notepad, create a new text file, with the following content:
<br /><br />
<pre>1=IIS,1,false,""<br />1.srv=localhost,"coldfusion"<br />1.cfmx=true,C:/inetpub/wwwroot<br /></pre>
</li>
<li>Save the file as C:\ColdFusion9\runtime\lib\wsconfig\wsconfig.properties</li>
<li>Extract jrun.dll and jrunwin32.dll from C:\ColdFusion9\runtime\lib\wsconfig.jar<ol type="a">
<li>To extract JAR files, you can use Java's JDK. Download from <a href="http://java.sun.com/javase/downloads/index.jsp">http://java.sun.com/javase/downloads/index.jsp</a> and install.</li>
<li>Locate JAR.EXE. On my server, it's in C:\Program Files\Java\jdk1.6.0_18\bin.</li>
<li>In a Command Prompt window, navigate to C:\Temp and enter the following commands (adjusting for the actual location of your JAR.EXE file):
<br /><br />
<pre>"C:\Program Files\Java\jdk1.6.0_18\bin\jar.exe" xf C:\ColdFusion9\runtime\lib\wsconfig.jar connectors/installers/intel-win/prebuilt/jrunwin32.dll<br />"C:\Program Files\Java\jdk1.6.0_18\bin\jar.exe" xf C:\ColdFusion9\runtime\lib\wsconfig.jar connectors/isapi/intel-win/prebuilt/jrun.dll<br />copy connectors\installers\intel-win\prebuilt\jrunwin32.dll C:\ColdFusion9\runtime\lib\wsconfig<br />copy connectors\isapi\intel-win\prebuilt\jrun.dll C:\ColdFusion9\runtime\lib\wsconfig\1<br /></pre>
</li>
</ol></li>
<li>With Notepad, create a new text file, with the following content:
<br /><br />
<pre>proxyservers=127.0.0.1:51800</pre>
</li>
<li>Save the file as C:\ColdFusion9\runtime\lib\wsconfig\1\jrunserver.store.</li>
<li>With Notepad, create a new text file, with the following content:
<br /><br />
<pre>verbose=false<br />scriptpath=/JRunScripts/jrun.dll<br />serverstore=C:/ColdFusion9/runtime/lib/wsconfig/1/jrunserver.store<br />bootstrap=127.0.0.1:51800<br />apialloc=false<br />ssl=false<br />ignoresuffixmap=false<br />#errorurl=<optionally redirect to this URL on errors><br /></pre>
</li>
<li>Save the file as C:\ColdFusion9\runtime\lib\wsconfig\1\jrun.ini.</li>
<li>Using the IIS Management Console, add the JRun Connector Filter to the IIS Master Properties.<ol type="a">
<li>Launch the IIS Management Console, at Start > Programs > Administrative Tools > Internet Services Manager</li>
<li>Select (right-click) the web server > Properties > Master Properties > WWW Service > Edit...</li>
<li>Select the "ISAPI Filter" tab and press the "Add" button.
<ul>
<li>Filter Name: JRun Connector Filter</li>
<li>Executable: C:\ColdFusion9\runtime\lib\wsconfig\1\jrun.dll</li>
</ul>
</li>
<li>Select the "Home Directory" tab and press the "Configuration..." button.</li>
<li>Add extensions for .jsp, .jws, .cfm, .cfml, .cfc, .cfr, and .cfswf, with the following parameters:
<ul>
<li>Executable: C:\ColdFusion9\runtime\lib\wsconfig\1\jrun.dll</li>
<li>Verbs: All verbs</li>
<li>Script engine: yes</li>
<li>Check that file exists: yes [Necessary if you specify site-specific 404 handlers in IIS. Otherwise, if you use CF's server-wide Missing Template Handler, no.]</li>
</ul>
</li>
<li>For each IIS Web Site with ColdFusion templates, add a JRunScripts virtual directory.<ol type="i">
<li>Select (right-click) an IIS Web Site > New > Virtual Directory
<ul>
<li>Alias: JRunScripts</li>
<li>Directory: C:\ColdFusion9\runtime\lib\wsconfig\1\</li>
<li>Read: yes</li>
<li>Run Scripts: yes</li>
<li>Execute: yes</li>
<li>Write: no</li>
<li>Browse: no</li>
</ul>
</li>
<li>Repeat for each IIS Web Site</li>
</ol></li>
</ol>
<ul>
</ul>
</li>
<li>Restart your server.</li>
</ol>
<p>That should do it. Point your web browser to the IIS server's default website (e.g., http://localhost/cfide/administrator/index.cfm) to complete the ColdFusion 9 installation wizard and access the ColdFusion Administrator.</p>
<p>If you found this article helpful, please check out <a href="http://www.circa3000.com">Circa 3000</a> for your ColdFusion hosting needs. Since 1998 (that is, ColdFusion 3.1), Circa 3000 has held the honor of "original ColdFusion specialty host." My company is uniquely service- and relationship-driven, and serves only as many customers as I can personally manage. If you've been burned by budget, volume-driven hosts who don't know what a "datasource" is, please give me a call, at 800-CIRCA3K (800-247-2235). I look forward to hearing from you!</p>
<p>
<!--
<p>Some have commented (e.g., http://www.codecurry.com/2010/01/coldfusion-manual-configuration-issues.html) that Coldfusion 8 and 9 employ a default port of 51800. However, my silent install of CF 9 chose a default port of 51011, the same default port used by CFMX 7. If your ports don't match up properly, you'll log the following error: "Couldn't initialize from remote server, JRun server(s) probably down."</p>
--></p>
Install Kai's Power Tools (KTP) 3, 5 and 6 on Windows Vista
urn:uuid:44454218-7E98-2630-CB4C90956A2127A6
2008-04-19T11:04:00Z
2010-03-09T11:03:00Z
<p>Kai's Power Tools (KPT) versions 3, 5 and 6, from MetaTools/MetaCreations will not install on Microsoft's Windows Vista. Of course, you could upgrade to Corel's KPT suite, but why spend money on software you already own? Fortunately, there's a workaround. This article provides step-by-step instructions for recovering your precious KPT 3, 5 and 6 plug-ins on Vista.</p>
Dave Delbridge
<p>If you've tried to install your old-school (e.g., MetaTools, MetaCreations) Kai's Power Tools on Microsoft Windows Vista, you've certainly discovered that the installers, like so, so many others of their generation, are incompatible with Vista. Don't even bother with Vista's "Compatibility Mode;" it won't help. Sure, you could purchase the newer KPT suite from Corel, but this collection doesn't include <em>all </em>of the tools from KPT 3, 5 and 6. <em>Whatever will you do without Spheroid Designer?!</em> Furthermore, you've probably just emptied your bank account on Adobe suite upgrades for Vista compatibility. Now, do you really want to purchase a "best of" collection of KPT when you already own the complete works? </p>
<p>Thankfully, there's a solution. Kai's power tools aren't themselves executables but Photoshop plug-ins and, as such, you need only extract the contents of your KPT 3, 5 and 6 CD-ROMs in order to install the respective files into your imaging apps. Here's how:</p>
<ol>
<li>Install KPT 3, 5 or 6 on a pre-Vista computer (e.g., Windows 95, NT, 2000, XP). <em>Of course, if your prior installation of KPT is still available, you can retrieve the files from that PC without reinstallation.</em> </li>
<li>By default, the KPT 3 installer places the KPT files in C:\Win32App\KPT. Later versions prompt for your Photoshop Plug-Ins directory, but note that you needn't have Photoshop installed on the target computer in order to proceed with the installation. For this article, I've installed KPT 5 and 6 to C:\Win32App\KPT5 and C:\Win32App\KPT6, respectively. <em>Can't find the files? Mixed 'em together? A complete file listing for KPT versions 3, 5 and 6 is supplied below.</em></li>
<li>KPT 3 also installs KPT3HUB.DLL and KPT3HELP.HLP in C:\<em><windows root></em>.</li>
<li>KPT 6 also installs KPTW600.TXT in C:\<em><windows root></em>\MetaCreations.</li>
<li>In accordance with the License Agreement, backup the directory (and subs) and any files from steps #3 and #4 to CD-R so that future installations won't require the older OS. <em>While you're at it, you might as well paste a copy of these instructions in there.</em> </li>
<li>Copy the directory (and subs) to your Vista PC's Photoshop plug-ins directory. For example, in Photoshop CS3 on Windows Vista, the default plug-ins directory is C:\Program Files\Adobe\Adobe Photoshop CS3\Plug-Ins. Copy each KPT installation to a separate subdirectory of the aforementioned Plug-Ins folder. For example, I've copied each KPT version to the following directories, respectively:
<ul>
<li>C:\Program Files\Adobe\Adobe Photoshop CS3\Plug-Ins\KPT 3</li>
<li>C:\Program Files\Adobe\Adobe Photoshop CS3\Plug-Ins\KPT 5</li>
<li>C:\Program Files\Adobe\Adobe Photoshop CS3\Plug-Ins\KPT 6</li>
</ul>
</li>
<li>Copy any files from steps #3 and #4 to their respective locations in Vista.</li>
</ol>
<p>That should do it. Fire up Photoshop and get weird with your ol' KPT faves. Enjoy!</p>
<p><strong>KPT 3 Installed Files<br /></strong></p>
<ul>
<li>C:\Win32App\KPT\DeIsL1.isu</li>
<li>C:\Win32App\KPT\EREG1_32.DLL</li>
<li>C:\Win32App\KPT\EREGLB32.DLL</li>
<li>C:\Win32App\KPT\KPT3READ.WRI</li>
<li>C:\Win32App\KPT\KPT3_DR.8BF</li>
<li>C:\Win32App\KPT\KPT3_GD.8BF</li>
<li>C:\Win32App\KPT\KPT3_GD.PRS</li>
<li>C:\Win32App\KPT\KPT3_GL.8BF</li>
<li>C:\Win32App\KPT\KPT3_IF.8BF</li>
<li>C:\Win32App\KPT\KPT3_IF.PRS</li>
<li>C:\Win32App\KPT\KPT3_KS.8BF</li>
<li>C:\Win32App\KPT\KPT3_PC.8BF</li>
<li>C:\Win32App\KPT\KPT3_PQ.8BF</li>
<li>C:\Win32App\KPT\KPT3_SD.8BF</li>
<li>C:\Win32App\KPT\KPT3_SD.PRS</li>
<li>C:\Win32App\KPT\KPT3_SN.8BF</li>
<li>C:\Win32App\KPT\KPT3_TC.8BF</li>
<li>C:\Win32App\KPT\KPT3_TE.8BF</li>
<li>C:\Win32App\KPT\KPT3_TE.PRS</li>
<li>C:\Win32App\KPT\KPT3_VT.8BF</li>
<li>C:\Win32App\KPT\KPT3_WL.8BF</li>
<li>C:\Win32App\KPT\REGISTER.EXE</li>
<li>C:\<em><windows root></em>\KPT3HUB.DLL</li>
<li>C:\<em><windows root></em>\KPT3HELP.HLP</li>
</ul>
<p><strong>KPT 5 Installed Files</strong></p>
<ul>
<li>C:\Win32App\KPT5\DeIsL1.isu</li>
<li>C:\Win32App\KPT5\KPT5</li>
<li>C:\Win32App\KPT5\KPT5 ReadMe.WRI</li>
<li>C:\Win32App\KPT5\regkpt5.exe</li>
<li>C:\Win32App\KPT5\KPT5\FPXLIB.DLL</li>
<li>C:\Win32App\KPT5\KPT5\JPEGLIB.DLL</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Blurrrr.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Blurrrr_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Blurrrr_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 FiberOptix.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 FiberOptix_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 FiberOptix_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Frax4D.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Frax4D_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Frax4D_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 FraxFlame.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 FraxFlame_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 FraxFlame_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Fraxplorer.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Fraxplorer_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Fraxplorer_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Noize.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Noize_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Noize_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Orb-it.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Orb-it_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Orb-it_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 RadWarp.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 RadWarp_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 RadWarp_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 ShapeShifter.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 ShapeShifter_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 ShapeShifter_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Smoothie.8bf</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Smoothie_c.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5 Smoothie_ce.mcm</li>
<li>C:\Win32App\KPT5\KPT5\KPT5Hub.dll</li>
<li>C:\Win32App\KPT5\KPT5\kptaxiom.dll</li>
<li>C:\Win32App\KPT5\KPT5\kptaxiomui.dll</li>
<li>C:\Win32App\KPT5\KPT5\kptimageio.mcm</li>
<li>C:\Win32App\KPT5\KPT5\mCComponent.dll</li>
<li>C:\Win32App\KPT5\KPT5\mCEffect.dll</li>
<li>C:\Win32App\KPT5\KPT5\mCParmServer.dll</li>
<li>C:\Win32App\KPT5\KPT5\mCPresetManager.mcm</li>
<li>C:\Win32App\KPT5\KPT5\mCPSFilterSys.dll</li>
<li>C:\Win32App\KPT5\KPT5\metaos</li>
<li>C:\Win32App\KPT5\KPT5\mPlatformUtils.dll</li>
<li>C:\Win32App\KPT5\KPT5\mPSUtils.dll</li>
<li>C:\Win32App\KPT5\KPT5\prefs</li>
<li>C:\Win32App\KPT5\KPT5\presets</li>
<li>C:\Win32App\KPT5\KPT5\uisys.dll</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data</li>
<li>C:\Win32App\KPT5\KPT5\metaos\plugins</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\background.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\basepanel.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\bumppanel.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\chopsitem.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\colorpicker.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\defaults.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\environpanel.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\filmstrip.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\fraxpanel.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\glowpanel.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\gradientitem.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\imageio.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 Blurrrr.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 FiberOptix.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 Frax4D.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 FraxFlame.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 FraxPlorer.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 Noize.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 Orb-It.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 RadWarp.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 ShapeShifter.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\KPT5 Smoothie.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\layeritem.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\lightpanel.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\memdots.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\modaldialog.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\popupmenu.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\PresetManager.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\previewitem.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\shadowpanel.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\shapepanel.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\splash.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\system.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\data\topmaskpanel.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\plugins\Gif.8bi</li>
<li>C:\Win32App\KPT5\KPT5\metaos\plugins\psplugindata.dat</li>
<li>C:\Win32App\KPT5\KPT5\metaos\plugins\pspluginexceptionswindows.txt</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\Blurs.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\Fiber.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\Frax4D.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\FraxFlame.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\FraxPlorer.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\KPT 5 User Guide.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\KPT Basics.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\KPT Tutorials.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\Noise.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\RadWarp.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\ShapeShift.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\Smoothie.pdf</li>
<li>C:\Win32App\KPT5\KPT5\metaos\User Guide\Sphere.pdf</li>
<li>C:\Win32App\KPT5\KPT5\prefs\Blurrrr.last</li>
<li>C:\Win32App\KPT5\KPT5\prefs\Frax4D.last</li>
<li>C:\Win32App\KPT5\KPT5\prefs\FraxFlame.last</li>
<li>C:\Win32App\KPT5\KPT5\prefs\FraxPlorer.last</li>
<li>C:\Win32App\KPT5\KPT5\prefs\Noize.last</li>
<li>C:\Win32App\KPT5\KPT5\prefs\Orb-It.last</li>
<li>C:\Win32App\KPT5\KPT5\prefs\RadWarp.last</li>
<li>C:\Win32App\KPT5\KPT5\prefs\ShapeShifter.last</li>
<li>C:\Win32App\KPT5\KPT5\prefs\Smoothie.last</li>
<li>C:\Win32App\KPT5\KPT5\presets\Blurrrr</li>
<li>C:\Win32App\KPT5\KPT5\presets\EnvMaps</li>
<li>C:\Win32App\KPT5\KPT5\presets\FiberOptix</li>
<li>C:\Win32App\KPT5\KPT5\presets\Frax4D</li>
<li>C:\Win32App\KPT5\KPT5\presets\FraxFlame</li>
<li>C:\Win32App\KPT5\KPT5\presets\FraxPlorer</li>
<li>C:\Win32App\KPT5\KPT5\presets\Gradients</li>
<li>C:\Win32App\KPT5\KPT5\presets\Lights</li>
<li>C:\Win32App\KPT5\KPT5\presets\Noize</li>
<li>C:\Win32App\KPT5\KPT5\presets\Orb-It</li>
<li>C:\Win32App\KPT5\KPT5\presets\RadWarp</li>
<li>C:\Win32App\KPT5\KPT5\presets\ShapeShifter</li>
<li>C:\Win32App\KPT5\KPT5\presets\Smoothie</li>
<li>C:\Win32App\KPT5\KPT5\presets\Blurrrr\Blurrrr Basics</li>
<li>C:\Win32App\KPT5\KPT5\presets\EnvMaps\basic enviro</li>
<li>C:\Win32App\KPT5\KPT5\presets\FiberOptix\basic fur</li>
<li>C:\Win32App\KPT5\KPT5\presets\Frax4D\Frax4dbasic</li>
<li>C:\Win32App\KPT5\KPT5\presets\FraxFlame\Flame Basic</li>
<li>C:\Win32App\KPT5\KPT5\presets\FraxPlorer\Frax basic</li>
<li>C:\Win32App\KPT5\KPT5\presets\FraxPlorer\Frax basic 2</li>
<li>C:\Win32App\KPT5\KPT5\presets\Gradients\Grads 1</li>
<li>C:\Win32App\KPT5\KPT5\presets\Gradients\Grads 2</li>
<li>C:\Win32App\KPT5\KPT5\presets\Gradients\Grads 3</li>
<li>C:\Win32App\KPT5\KPT5\presets\Lights\basic lights</li>
<li>C:\Win32App\KPT5\KPT5\presets\Noize\noise examples</li>
<li>C:\Win32App\KPT5\KPT5\presets\RadWarp\Basic warps</li>
</ul>
<p>KPT 6 Installed Files</p>
<ul>
<li>C:\Win32App\KPT6\KPT6</li>
<li>C:\Win32App\KPT6\KPT6\FPXLIB.DLL</li>
<li>C:\Win32App\KPT6\KPT6\JPEGLIB.DLL</li>
<li>C:\Win32App\KPT6\KPT6\KPT Equalizer.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT Equalizer_c.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Equalizer_ce.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Gel.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT Gel_c.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Gel_ce.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Goo.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT Goo_c.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Goo_ce.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT LensFlare.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT LensFlare_c.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT LensFlare_ce.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Materializer.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT Materializer_c.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Materializer_ce.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Projector.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT Projector_c.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Projector_ce.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Reaction.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT Reaction_c.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Reaction_ce.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT SceneBuilder.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT SkyEffects.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT Turbulence.8bf</li>
<li>C:\Win32App\KPT6\KPT6\KPT Turbulence_c.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT Turbulence_ce.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPT6.dta</li>
<li>C:\Win32App\KPT6\KPT6\KPT6Hub.dll</li>
<li>C:\Win32App\KPT6\KPT6\KPT6Unin.isu</li>
<li>C:\Win32App\KPT6\KPT6\kptaxiom.dll</li>
<li>C:\Win32App\KPT6\KPT6\kptaxiomui.dll</li>
<li>C:\Win32App\KPT6\KPT6\kptimageio.mcm</li>
<li>C:\Win32App\KPT6\KPT6\KPTSCBLD</li>
<li>C:\Win32App\KPT6\KPT6\KPTSKYE</li>
<li>C:\Win32App\KPT6\KPT6\mCComponent.dll</li>
<li>C:\Win32App\KPT6\KPT6\mCEffect.dll</li>
<li>C:\Win32App\KPT6\KPT6\mCParmServer.dll</li>
<li>C:\Win32App\KPT6\KPT6\mCPresetManager.mcm</li>
<li>C:\Win32App\KPT6\KPT6\mCPSFilterSys.dll</li>
<li>C:\Win32App\KPT6\KPT6\metaos</li>
<li>C:\Win32App\KPT6\KPT6\mPlatformUtils.dll</li>
<li>C:\Win32App\KPT6\KPT6\mPSUtils.dll</li>
<li>C:\Win32App\KPT6\KPT6\Objects</li>
<li>C:\Win32App\KPT6\KPT6\Prefs</li>
<li>C:\Win32App\KPT6\KPT6\Presets</li>
<li>C:\Win32App\KPT6\KPT6\ReadMes</li>
<li>C:\Win32App\KPT6\KPT6\RegKPT6.exe</li>
<li>C:\Win32App\KPT6\KPT6\uisys.dll</li>
<li>C:\Win32App\KPT6\KPT6\KPTSCBLD\KPTSCBLDX.DTA</li>
<li>C:\Win32App\KPT6\KPT6\KPTSKYE\Bank1.sdx</li>
<li>C:\Win32App\KPT6\KPT6\KPTSKYE\Bank2.sdx</li>
<li>C:\Win32App\KPT6\KPT6\KPTSKYE\Bank3.sdx</li>
<li>C:\Win32App\KPT6\KPT6\KPTSKYE\Bank4.sdx</li>
<li>C:\Win32App\KPT6\KPT6\KPTSKYE\Bank5.sdx</li>
<li>C:\Win32App\KPT6\KPT6\KPTSKYE\KPTSKYEX.dta</li>
<li>C:\Win32App\KPT6\KPT6\KPTSKYE\user.sdx</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Defaults</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Plugins</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\backgroundX.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\basepanel.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\colorpicker.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\filmstrip.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\gradientitem.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\imageio.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\KPT Equalizer.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\KPT Gel_.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\KPT Goo_.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\KPT LensFlare.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\KPT Materializer.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\KPT Projector.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\KPT Reaction.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\KPT Turbulence.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\lightpanel.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\makemovie.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\memdots.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\modaldialog.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\popupmenu.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\PresetManager.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\previewitem.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\splashX.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Data\system.dat</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Defaults\Equalizer.def</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Defaults\Gel.def</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Defaults\Goo.def</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Defaults\LensFlare.def</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Defaults\Materializer.def</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Defaults\Projector.def</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Defaults\Reaction.def</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Defaults\Turbulence.def</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Plugins\Gif.8bi</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Plugins\kptAVIExport.brm</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Plugins\kptBMPSeqExport.brm</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Plugins\kptQTExport.brm</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Plugins\pspluginexceptionsmac.txt</li>
<li>C:\Win32App\KPT6\KPT6\metaos\Plugins\pspluginexceptionswindows.txt</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT Basics.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT Equalizer.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT Gel.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT Goo.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT LensFlare.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT Materializer.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT Projector.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT Reaction.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT SceneBuilder.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT SkyEffects.pdf</li>
<li>C:\Win32App\KPT6\KPT6\metaos\User Guide\KPT Turbulence.pdf</li>
<li>C:\Win32App\KPT6\KPT6\Objects\apple.PTC</li>
<li>C:\Win32App\KPT6\KPT6\Objects\cube.PTC</li>
<li>C:\Win32App\KPT6\KPT6\Objects\flying saucer.PTC</li>
<li>C:\Win32App\KPT6\KPT6\Objects\Objects ReadMe.txt</li>
<li>C:\Win32App\KPT6\KPT6\Objects\pin.PTC</li>
<li>C:\Win32App\KPT6\KPT6\Objects\sphere1.PTC</li>
<li>C:\Win32App\KPT6\KPT6\Objects\torus.PTC</li>
<li>C:\Win32App\KPT6\KPT6\Presets\EnvMaps</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Equalizer</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Gel</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Gradients</li>
<li>C:\Win32App\KPT6\KPT6\Presets\LensFlare</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Lights</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Materializer</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Projector</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Reaction</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Turbulence</li>
<li>C:\Win32App\KPT6\KPT6\Presets\EnvMaps\Maps 1.envm</li>
<li>C:\Win32App\KPT6\KPT6\Presets\EnvMaps\Maps 2.envm</li>
<li>C:\Win32App\KPT6\KPT6\Presets\EnvMaps\Maps 3.envm</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Equalizer\Eq. Basics</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Gel\Gel Basics</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Gel\More Gel</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Gradients\Grads 1</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Gradients\Grads 2</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Gradients\Grads 3</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Gradients\Subtle Grads</li>
<li>C:\Win32App\KPT6\KPT6\Presets\LensFlare\Flare Basics</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Lights\Basic Lights</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Lights\More Lights</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Materializer\Material Basics</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Projector\Projector Basics</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Reaction\Reaction Basics</li>
<li>C:\Win32App\KPT6\KPT6\Presets\Turbulence\Turb. Basics</li>
<li>C:\Win32App\KPT6\KPT6\ReadMes\KPT6ReadMe.txt</li>
<li>C:\Win32App\KPT6\KPT6\ReadMes\MetaSupport.pdf</li>
<li>C:\Win32App\KPT6\KPT6\ReadMes\TechTips.txt</li>
<li>C:\<em><windows root></em>\MetaCreations\KPTW600.TXT</li>
</ul>
<p> </p>