<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>I Prefer Jim</title>
	
	<link>http://www.ipreferjim.com</link>
	<description>Developer James Schubert shares his code and his thoughts.</description>
	<lastBuildDate>Tue, 01 May 2012 15:48:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ipreferjim" /><feedburner:info uri="ipreferjim" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by-nd/3.0/</creativeCommons:license><image><link>http://creativecommons.org/licenses/by-nd/3.0/</link><url>http://creativecommons.org/images/public/somerights20.gif</url><title>Some Rights Reserved</title></image><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/ipreferjim" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2Fipreferjim" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><item>
		<title>[node.js] Simple Logging in tweeter.js</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/wDeIcIwG1q0/</link>
		<comments>http://www.ipreferjim.com/2012/04/node-js-simple-logging-in-tweeter-js/#comments</comments>
		<pubDate>Mon, 30 Apr 2012 22:28:21 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[nodejs]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=883</guid>
		<description><![CDATA[tweeter.js is a simple OAuth implementation I started working on for a node.js application I had envisioned. The library works, as in it runs through the whole OAuth dance and allows the client to make API calls. There are some more in-depth things I never got around to (like caching the tokens and clearing sessions [...]]]></description>
			<content:encoded><![CDATA[<p><strong>tweeter.js</strong> is a simple OAuth implementation I started working on for a node.js application I had envisioned. The library works, as in it runs through the whole OAuth dance and allows the client to make API calls. There are some more in-depth things I never got around to (like caching the tokens and clearing sessions and whatnot) before I realized I don't like Twitter.  Oh well.</p>
<p>I was just looking through my github repositories and I thought it would be cool to post about the simple logging mechanism I created for tweeter.js. Although not the coolest pattern I used in the project (which probably goes to mixins), I like how simple the solution is.  Check out <a href="https://github.com/jimschubert/tweeter.js" title="tweeter.js on github" target="_blank">the code</a> for other cool features..</p>
<h2>Logging</h2>
<p>The cool thing about this logging framework is that it allows you to write out logs to different streams.  For instance, suppose you want to write all logging information other than errors to log.txt, but you want to keep errors in errors.txt.</p>
<p>The way I implemented this was to create an object of <em>streams</em> on the <em>Log</em> object. I used getters/setters to provide validation that an object being assigned to one of the properties is actually a stream. Although I didn't bother with it, this object could possibly be sealed or frozen.</p>
<pre class="brush: jscript; title: ; notranslate">
// An object with safe getters/setters for each stream.
// Streams are:
// debug, info, error, warn
Log.prototype.streams = {
    get none() { return { write: function() { }}; },
    get debug() { return this._debug; },
    set debug(val) {
        requiresStream(val);
        this._debug = val;
    },
    get info() { return this._info; },
    set info(val) {
        requiresStream(val);
        this._info = val;
    },
    get warn() { return this._warn; },
    set warn(val) {
        requiresStream(val);
        this._warn = val;
    },
    get error() { return this._error; },
    set error(val) {
        requiresStream(val);
        this._error = val;
    }
}
</pre>
<p>Because this is written for node.js, <strong>requiresStream()</strong> verifies the value is an instance of EventEmitter with a write function. </p>
<p>Defaults for these streams are set in the constructor with a default logLevel of -1 (disabled).</p>
<pre class="brush: jscript; title: ; notranslate">
var Log = module.exports = exports = function Log(level) {
    // default error to stderr and the rest to stdout
    this.streams.debug = process.stdout;
    this.streams.info = process.stdout;
    this.streams.warn = process.stdout;
    this.streams.error = process.stderr;

    // default the logLevel to disabled
    this.logLevel = level || -1;
}
</pre>
<p>An interesting thing about this logger is how I make the calling convention flexible. I use .NET regularly and I would call a logging function in .NET with an enum value to specify the logLevel.  I wanted a similar functionality in this logger, so I created a lookup object to map a key (i.e. DEBUG) to a logLevel (0) and a stream (debug).</p>
<pre class="brush: jscript; title: ; notranslate">
// [DISABLED] else [DEBUG &gt; INFO &gt; WARN &gt; ERROR]
Log.prototype.logLevels = {
    DISABLED:   { value: -1, stream: 'none' },
    DEBUG:      { value: 0, stream: 'debug' },
    INFO:       { value: 1, stream: 'info' },
    WARN:       { value: 2, stream: 'warn' },
    ERROR:      { value: 3, stream: 'error' }
}
</pre>
<p>I considered accessing these on the streams object directly, but did it this way for readability and flexibility.  A major deciding factor in choosing this route was the ability to reorder logging levels in a single place in the code.</p>
<pre class="brush: jscript; title: ; notranslate">
// ## log(level msg);
// logs the output with a nice colorful indicator of the stream.
// `msg` may be a string or a formattable string and options.
Log.prototype.log = function(level, msg) {
    var original = level;
    try {
        if(typeof level === 'string'){
            level = this.logLevels[level.toUpperCase()];
        }
        // get logLevel value
        if( (this.logLevel &gt; -1) &amp;&amp; (level.value &gt;= this.logLevel) ) {
            var stream = this.streams[level.stream];
            stream.write( util.format.call(this, '[&#92;&#48;33[%sm%s&#92;&#48;33[39m]\t', colors[level.value], level.stream) );
            stream.write( util.format.apply(this, slice.call(arguments,1) ) + '\n');
        }
    } catch (err) {
        console.error(&quot;logging is improperly configured!\nIs %j a supported logLevel?\nError:\n%j\n&quot;,original, err);
    }
}
</pre>
<h2>An example</h2>
<p>I've <a href="https://github.com/jimschubert/blogs/tree/master/2012-04-30" title="blog example on github" target="_blank">uploaded</a> an example to github.</p>
<p>In this example, I write out logs for each of the 4 supported levels.  The default is to write these out to stdout.  After writing to the defaults, I set </p>
<pre class="brush: jscript; title: ; notranslate">
var Log = require('./log.js'),
    fs = require('fs');

var level = process.argv[2] || 1;
var logger = new Log(level),
    level = logger.logLevels;

logger.log(level.DEBUG, &quot;This is a debug message&quot;);
logger.log(level.INFO, &quot;This is an info message&quot;);
logger.log(level.WARN, &quot;This is a warning message&quot;);
logger.log(level.ERROR, &quot;This is an error message&quot;);

var debugStream = fs.createWriteStream('./debug.txt');
var infoStream = fs.createWriteStream('./info.txt');
var warnStream = fs.createWriteStream('./warn.txt');
var errorStream = fs.createWriteStream('./error.txt');

logger.streams.debug = debugStream;
logger.streams.info = infoStream;
logger.streams.warn = warnStream;
logger.streams.error = errorStream;

logger.log(level.DEBUG, &quot;This is a debug message&quot;);
logger.log(level.INFO, &quot;This is an info message&quot;);
logger.log(level.WARN, &quot;This is a warning message&quot;);
logger.log(level.ERROR, &quot;This is an error message&quot;);

debugStream.end();
infoStream.end();
warnStream.end();
errorStream.end();
</pre>
<p>This provides the following input when passing a log level in via the command line:</p>
<p><a href="http://www.ipreferjim.com/site/wp-content/uploads/2012/04/log.js-example.png?9d7bd4"><img src="http://www.ipreferjim.com/site/wp-content/uploads/2012/04/log.js-example.png?9d7bd4" alt="" title="log.js-example" width="724" height="463" class="aligncenter size-full wp-image-885" /></a></p>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=883&amp;md5=09d776460eff273e81aa1c24e5761fcb" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/eRPaE0991AWKJY8vSYAQzYur-BQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/eRPaE0991AWKJY8vSYAQzYur-BQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/eRPaE0991AWKJY8vSYAQzYur-BQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/eRPaE0991AWKJY8vSYAQzYur-BQ/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/wDeIcIwG1q0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/04/node-js-simple-logging-in-tweeter-js/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F04%2Fnode-js-simple-logging-in-tweeter-js%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=%5Bnode.js%5D+Simple+Logging+in+tweeter.js&amp;description=tweeter.js+is+a+simple+OAuth+implementation+I+started+working+on+for+a+node.js+application+I+had+envisioned.+The+library+works%2C+as+in+it+runs+through+the+whole+OAuth+dance+and...&amp;tags=Javascript%2Cnodejs%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/04/node-js-simple-logging-in-tweeter-js/</feedburner:origLink></item>
		<item>
		<title>ASP.NET, AppDomains, and shadow-copying</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/SsGwbfTI0R0/</link>
		<comments>http://www.ipreferjim.com/2012/04/asp-net-appdomains-and-shadow-copying/#comments</comments>
		<pubDate>Sun, 29 Apr 2012 22:05:28 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Advanced]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=853</guid>
		<description><![CDATA[I answered a question on StackOverflow nearly two years ago, and I'm surprised at how few votes it has received, despite comments such as: +1 for teaching me something new today thanks. -kobe Being one of my favorite answers, I thought I should discuss it on my blog a little more in-depth than just posting [...]]]></description>
			<content:encoded><![CDATA[<p>I answered a <a href="http://stackoverflow.com/a/4394472/151445" title="Does my ASP.NET application stop executing if I overwrite the DLLs?" target="_blank">question on StackOverflow</a> nearly two years ago, and I'm surprised at how few votes it has received, despite comments such as:</p>
<blockquote><p>+1 for teaching me something new today thanks. -kobe</p></blockquote>
<p>Being one of my favorite answers, I thought I should discuss it on my blog a little more in-depth than just <a href="http://www.ipreferjim.com/2011/07/what-happens-when-i-overwrite-a-dll-asp-net/" title="Previous post" target="_blank">posting the SO answer</a>.  I'd like to briefly discuss what ASP.NET really is (in the context of IIS), why AppDomains are needed, and lastly what shadow-copying does for an application.  There is no code associated with this post, and it is driven more by contemplation than by a specific resolution to a problem. So, I apologize in advance if it seems disjointed at times.</p>
<p><span id="more-853"></span></p>
<h2>What is an ASP.NET application?</h2>
<p>When I first started using the .NET Framework, I was somewhat confused about how applications actually ran considering an assembly is a <a href="http://en.wikipedia.org/wiki/Portable_Executable#.NET.2C_metadata.2C_and_the_PE_format" title="Portable Executable on Wikipedia" target="_blank">PE format</a> with some CLR headers and CLR data. What this means (and it makes a lot of sense) is that the CLR is really just a COM application hosting a runtime environment (the CLR).</p>
<p>I usually consider programming languages like C# to be compiled into a binary, but the CLR really only operates on IL.  This means C# et al. are simply abstractions to execute "just-in time"-compiled code in a compartmentalized sandbox within an instance of the CLR. The compartmentalization is further secured using AppDomains to prevent (or attempt to prevent) applications from destroying data in other AppDomains. It makes sense, but I've never really seen it put so simply before. Even though I knew this to be the case and understood how it all worked, my thoughts of the CLR were also compartmentalized. When I stepped back and looked at it, I thought to myself, "Wait, what? That's it?" Why I thought the CLR was some sort of voodoo is beyond me.</p>
<p>An ASP.NET application is .NET code written against a framework (ASP.NET), executing in a runtime (CLR), which is in turn hosted in a (COM) process (IIS).  <em>That's all there is to it, there's no magic.</em> It's been a few years since I learned this, but I seem to still encounter developers with the same years of experience or more who don't see how these pieces are integrated.  It really only takes a little exploration on your system to get a better picture of the whole environment.</p>
<h2>IIS</h2>
<p>If you take a look at an IIS assembly in <a href="http://www.safer-networking.org/en/filealyzer/index.html" title="FileAlyzer by Safer Networking" target="_blank">FileAlyzer</a>, you might see <a href="http://msdn.microsoft.com/en-us/library/99sz37yh.aspx" title="CorBindToRuntimeEx" target="_blank">CorBindToRuntimeEx</a> or <a href="http://msdn.microsoft.com/en-us/library/dd537633.aspx" title="CLRCreateInstance" target="_blank">CLRCreateInstance</a> listed as PE Imports. This is because IIS manages the creation of multiple CLR instances and multiple AppDomains per instance.  ASP.NET is implemented as an <a href="http://msdn.microsoft.com/en-us/library/ms524610.aspx" title="ISAPI Filter Overview on MSDN" target="_blank">ISAPI extension</a> within IIS.</p>
<p>In fact, <strong>%WinDir%\Microsoft.NET\Framework\[Version]\aspnet_regiis.exe</strong> imports <em>RegisterAspNetEx</em> from webengine.dll. Running</p>
<pre class="brush: bash; title: ; notranslate">
dumpbin /imports webengine.dll
</pre>
<p>will output all header information, in which you will see mscoree.dll is delay-loaded and provides the CLR creation methods (from .NET 2.0):</p>
<pre class="brush: plain; title: ; notranslate">
mscoree.dll
              00000001 Characteristics
              6A301BB8 Address of HMODULE
              6A2FE1C4 Import Address Table
              6A2FB5D4 Import Name Table
              00000000 Bound Import Name Table
              00000000 Unload Import Name Table
                     0 time date stamp

          6A2FAC25               0 CorBindToRuntimeEx
          6A2B292E               0 CorBindToRuntimeHost
          6A2B21C6               0 ClrCreateManagedInstance
</pre>
<p>Here we've found CorBindToRuntimeEx! This library is part of the COM application responsible for running the CLR instances that host ASP.NET AppDomains inside IIS. Cool, huh? That's the magic.</p>
<p>IIS is the hosting environment responsible for running the ASP.NET ISAPI filter.  Once ASP.NET is registered with IIS, webengine.dll handles the creation of CLR instances within Application Pools.  Inside those Application Pools, one or more AppDomains may exist.</p>
<p>There is a lot that has to go on under the hood in an ASP.NET application, but I'd like to discuss the management of application resources-- specifically <em>shadow copying</em>.</p>
<h2>Shadow Copying</h2>
<p><strong>Shadow copying</strong> is a technique used by ASP.NET to allow resources to remain available continuously without interfering with the execution of code in an AppDomain. Conceptually, it is a very simple idea. Unfortunately, most developers don't even know it is happening under the covers and I've seen production site get bitten by it in some weird configuration and file modification scenarios.</p>
<p>When shadow copying is enabled, ASP.NET copies certain resources (all assemblies) from the application directory into a temporary folder and those are the resources which remain in use during the life of an AppDomain. This cache is the same one used for downloaded assemblies and is cleaned by the CLR when the assemblies are no longer in use (akin to Garbage Collection of runtime resources). By default, the location for these cached assemblies will be something like</p>
<pre class="brush: plain; title: ; notranslate">
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\demo1\9b9144a7\8665ac07
</pre>
<p>As you can see, the directories are hashed in what (I assume) is similar to the hashing algorithm used for the GAC. If you like, you can set the <a href="http://msdn.microsoft.com/en-us/library/system.appdomainsetup.cachepath.aspx" title="AppDomainSetup.CachePath" target="_blank">AppDomainSetup.CachePath</a> property to shadow copy assemblies to a different location. You must also set the AppDomainSetup.ApplicationName property, otherwise CachePath will be ignored. One downside to this is that you'd have to create a new AppDomain to initialize these values and the management of assembly resolution may become cumbersome. You may also attempt setting the cache path as described <a href="http://stackoverflow.com/a/2847495/151445" title="AssemblyResolve event is not firing during compilation of a dynamic assembly for an aspx page on StackOverflow" target="_blank">here</a>:</p>
<pre class="brush: csharp; title: ; notranslate">
protected const string ApplicationAssembliesFolder = &quot;~/Assemblies&quot;;

    protected void Application_Start(object sender, EventArgs e)
    {
        var assembliesPath = Server.MapPath(ApplicationAssembliesFolder);

        AppDomain.CurrentDomain.SetShadowCopyPath(
            AppDomain.CurrentDomain.SetupInformation.ShadowCopyDirectories +
            Path.PathSeparator + assembliesPath);

        Assembly.LoadFrom(
            Path.Combine(assembliesPath, &quot;Example.dll&quot;));
    }
</pre>
<p>When changing the default location of shadow copied assemblies, be aware that ASP.NET no longer handles the clean up of the assemblies-- it is up to the application to maintain these assemblies.</p>
<h3>The shadow copying process</h3>
<p>The shadow copying process is kicked off any time an AppDomain recycle occurs.  Tess Ferrandez (who has a killer blog, you should check it out) lists some reasons why the AppDomain may be recycled in her post, <a href="http://blogs.msdn.com/b/tess/archive/2006/08/02/asp-net-case-study-lost-session-variables-and-appdomain-recycles.aspx" title="Tess Ferrandez's post" target="_blank">ASP.NET Case Study: Lost session variables and appdomain recycles</a>:</p>
<ul>
<li>Machine.Config, Web.Config or Global.asax are modified</li>
<li>The bin directory or its contents is modified</li>
<li>The number of re-compilations (aspx, ascx or asax) exceeds the limit specified by the &lt;compilation<br />
numRecompilesBeforeAppRestart=/&gt; setting in machine.config or web.config  (by default this is set to 15)</li>
<li>The physical path of the virtual directory is modified</li>
<li>The CAS policy is modified</li>
<li>The web service is restarted</li>
<li>(2.0 only) Application Sub-Directories are deleted (see Todd’s blog <a href="http://blogs.msdn.com/toddca/archive/2006/07/17/668412.aspx" title="http://blogs.msdn.com/toddca/archive/2006/07/17/668412.aspx" target="_blank">http://blogs.msdn.com/toddca/archive/2006/07/17/668412.aspx</a> for more info)</li>
</ul>
<p>My rule of thumb is to assume that anytime something happens which could change the execution of an application, the AppDomain will be recycled.</p>
<p>When an AppDomain is recycled, resources are shadow copied to a new location and any connections to the old AppDomain are 'drained', meaning they are allowed to finish on the old AppDomain but subsequent requests are handled by the new AppDomain. This allows the framework to create a fairly seamless experience, but is also part of the reason why many developers don't know about shadow copying.</p>
<h3>How shadow copied files are updated</h3>
<p>When using .NET 4, shadow copying assemblies in an application for which assemblies rarely ever change has improved. In previous versions of ASP.NET, there was often a noticeable delay in application startup time while assemblies were being shadow copied. Now, the framework checks the file date/time of an application's assemblies and compares that with the file date/time of any shadow copied assemblies.  If they are the same, the shadow copying process does not occur.  This causes the shadow copying process to kick off only if an assembly has been physically modified.  </p>
<p>Now, if these things are happening a lot and you either have <em>many</em> assemblies or your assemblies <em>change often</em>, .NET 4 is actually adding one extra step to the shadow copying process (checking file times).  You can disable this extra step by adding the following configuration to your web.config:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;configuration&gt;
   &lt;runtime&gt;
      &lt;shadowCopyVerifyByTimestamp enabled=&quot;false&quot; /&gt;
   &lt;/runtime&gt;
&lt;/configuration&gt;
</pre>
<p>The process itself includes the application location, a temporary location, and the shadow cache location.  The process would look something like this for each assembly:</p>
<ol>
<li>Copy assembly from application location to temporary location</li>
<li>Open assembly</li>
<li>Verify assembly name</li>
<li>Validate strong name</li>
<li>Compare update to current cached assembly</li>
<li>Copy to shadow copy location (if newer)</li>
<li>Remove assembly from temporary location</li>
</ol>
<p>That is a pretty hefty process if your application contains a lot of assemblies. You can surely see why the file time comparison introduced in .NET 4 is beneficial. This is also why applications with many, many resources take longer to "start up". The framework isn't executing the code directly from the application directory.</p>
<h3>Disabling shadow copying</h3>
<p>Shadow copying is important if you are modifying assemblies directly in a live application. If you are working with a load balancer in which you're able to drain connections from a server and stop IIS for deployment, you may benefit from disabling shadow copying altogether.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;hostingEnvironment shadowCopyBinAssemblies=&quot;false&quot; /&gt;
</pre>
<h3>Alternative configuration: Wait-Change Notification</h3>
<p>One modification I would suggest if you are swapping out assemblies regularly is to set the <em>maxWaitChangeNotification</em> and <em>waitChangeNotification</em> attributes on the <strong>httpRuntime</strong> element.  Both of these attributes take an Int32 value that, when combined, determine when the AppDomain recycling occurs because of a file change. </p>
<p>The <em>waitChangeNotification</em> attribute will modify how long the framework waits between file changes.  In other words, if File A finishes copying and <em>waitChangeNotification</em> is set to 2 seconds, the framework will wait 2 seconds for another file modification to occur before spawning a new AppDomain. If File B is modified within that time, it will again wait 2 seconds for another file to be modified.</p>
<p>If <em>maxWaitChangeNotification</em> is also set, the framework no longer chains the wait time. There is an absolute time from when the first file modification starts.  For instance, if <em>maxWaitChangeNotification</em> is set to 5 seconds, it doesn't matter if a file is in the process of being modified, a new AppDomain will be spawned based on the File A modification (operation 1).  The File B modification will begin the wait even of operation 2, after which another AppDomain will be spawned.  I've created the image below as an attempt to clarify what these settings do. These file copy operations represent changes to the application directory. The "AppDomain restart" indicators are the points at which shadow copying begins. Files that are being written are locked and not copied to the temporary location.</p>
<p><img src="https://docs.google.com/drawings/pub?id=1O0vztnL_TeXROG5EeyI4EsGtB1gxDkoVtRVjNoZZ6ko&amp;w=704&amp;h=260"></p>
<h3>Further Reading</h3>
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/dd380850.aspx" title="Hosting Overview on MSDN" target="_blank">Hosting Overview</a></li>
<li><a href="http://msdn.microsoft.com/en-us/magazine/cc163655.aspx" title="CLR Inside Out: Improving Application Startup Time on MSDN Magazine" target="_blank">CLR Inside Out: Improving Application Startup Time</a></li>
<li><a href="http://www.codeproject.com/Articles/1432/What-is-an-ISAPI-Extension" title="What is an ISAPI Extension? on CodeProject" target="_blank">What is an ISAPI extension?</a></li>
<li><a href="http://blog.kleegroup.com/teknics/?p=58" title="Inside IIS – Enregistrement d’ASP.Net dans IIS" target="_blank">Inside IIS – Enregistrement d’ASP.Net dans IIS</a></li>
<li><a href="http://msdn.microsoft.com/en-us/magazine/cc163567.aspx" title="CLR Hosting APIs on MSDN Magazine" target="_blank">CLR Hosting APIs</a></li>
<li><a href="http://stackoverflow.com/questions/10065070/modules-assemblies-headers-in-clr" title="Modules, Assemblies, Headers in CLR on StackOverflow" target="_blank">Modules, Assemblies, Headers in CLR</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ms404279.aspx" title="Shadow Copying Assemblies on MSDN" target="_blank">Shadow Copying Assemblies</a></li>
</ul>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=853&amp;md5=4243f4b0483d2741dd4340faadb37086" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/agu5b_gdD89O8ccPrJL6L7_U2LI/0/da"><img src="http://feedads.g.doubleclick.net/~a/agu5b_gdD89O8ccPrJL6L7_U2LI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/agu5b_gdD89O8ccPrJL6L7_U2LI/1/da"><img src="http://feedads.g.doubleclick.net/~a/agu5b_gdD89O8ccPrJL6L7_U2LI/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/SsGwbfTI0R0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/04/asp-net-appdomains-and-shadow-copying/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F04%2Fasp-net-appdomains-and-shadow-copying%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=ASP.NET%2C+AppDomains%2C+and+shadow-copying&amp;description=I+answered+a+question+on+StackOverflow+nearly+two+years+ago%2C+and+I%27m+surprised+at+how+few+votes+it+has+received%2C+despite+comments+such+as%3A+%2B1+for+teaching+me+something+new...&amp;tags=Advanced%2CASP.NET%2CC%23%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/04/asp-net-appdomains-and-shadow-copying/</feedburner:origLink></item>
		<item>
		<title>Allowing only a single instance of a .NET application</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/UBEdVuH-ZvU/</link>
		<comments>http://www.ipreferjim.com/2012/04/allowing-only-a-single-instance-of-a-net-application/#comments</comments>
		<pubDate>Mon, 23 Apr 2012 23:13:32 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Advanced]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=840</guid>
		<description><![CDATA[In the past, whenever I constrained an application to having only a single instance running at any given time, I naively walked a list of running processes to find a process with the same name as the currently-running process. If it exists, there's another instance, if not I would assume there is no other instance. [...]]]></description>
			<content:encoded><![CDATA[<p>In the past, whenever I constrained an application to having only a single instance running at any given time, I naively walked a list of running processes to find a process with the same name as the currently-running process. If it exists, there's another instance, if not I would assume there is no other instance.  This was a quick and dirty approach, because I didn't know of any other way. Of course, this would fail if the user renamed the process; total fail.</p>
<p>In <a href="http://shop.oreilly.com/product/9780735627048.do" title="CLR via C#" target="_blank">CLR via C#</a> by Jeffrey Richter, a much quicker solution is presented (leaving my naive solution to be only <em>dirty</em>). This solution uses a <a href="http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx" title="System.Threading.Semaphore" target="_blank">Semaphore</a> to count references to a resource (the application) as it will be managed by the operating system.</p>
<p>Here is a simple console application to display how this would work:</p>
<pre class="brush: csharp; title: ; notranslate">
    class Program
    {
        const string Id = &quot;af49d266-e4f4-4a63-b73c-f62c1144b584&quot;;
        static void Main(string[] args)
        {
            bool thisInstance;
            using (var semaphore = new Semaphore(0, 1, Id, out thisInstance))
            {
                if (thisInstance)
                {
                    Console.WriteLine(&quot;This is the first instance!&quot;);
                    Console.ReadLine();
                }
                else
                {
                    Console.WriteLine(&quot;There is another instance running.&quot;);
                    Console.ReadLine();
                }
            }
        }
    }
</pre>
<p>
<a href="http://www.ipreferjim.com/site/wp-content/uploads/2012/04/SingleInstance.png?9d7bd4"><img src="http://www.ipreferjim.com/site/wp-content/uploads/2012/04/SingleInstance-300x103.png?9d7bd4" alt="" title="SingleInstance" width="300" height="103" class="aligncenter size-medium wp-image-841" /></a>
</p>
<p>A semaphore is designed to limit access to a given resource.  If you read the <a href="http://en.wikipedia.org/wiki/Semaphore_(programming)" title="Semaphore on Wikipedia" target="_blank">Wikipedia - Semaphore</a> article, you'll see that a semaphore is described as a librarian handing out passes to study rooms. The librarian doesn't care who is in which room, only whether there are rooms available.  There could be 10 rooms, there could be 100.  In this single application example, we have 1 available resource which is the application identified by a constant Guid - "af49d266-e4f4-4a63-b73c-f62c1144b584". Because the operating system will use this string to uniquely identify our application, I've chosen a Guid over something simple like "MySemaphore" because the chances of a Guid being duplicated are theoretically nil.</p>
<p>Using this Semaphore constructor:</p>
<pre class="brush: csharp; title: ; notranslate">
public Semaphore(
	int initialCount,
	int maximumCount,
	string name,
	out bool createdNew
)
</pre>
<p>we can create a <em>binary semaphore</em>. </p>
<p>A binary semaphore allows us to have an on/off switch for running our application -- is the resource available or not?  When we have 1 resource available, and the first application starts up, it decrements the count of <em>available resources</em> to 0. If this decrement occurs, the <em>createdNew</em> out parameter will be true. On the other hand, if an application starts up and the semaphore's available resource count is 0, <em>createdNew</em> will be false.</p>
<p>Notice in the code above that Console.ReadLine() is used in each block of the if statement to block execution. <strong>Why is this not located at the end of the Main method?</strong> </p>
<p>It's because Semaphore is a type derived from <a href="http://msdn.microsoft.com/en-us/library/system.threading.waithandle.aspx" title="WaitHandle" target="_blank">WaitHandle</a>.  WaitHandle implements the IDisposable interface, which is why the Semaphore is wrapped in a using block.  When the code exits this using block, semaphore.Dispose() executes semaphore.Close() and the currently-held resource is released.  This increments the <em>available resources</em> back to the maximum value of 1. In a real application, the first block would call the Application's Run() method and the else block would either display a message, terminate silently, or switch to the first process.</p>
<p>It is also possible to have any subsequent processes wait for the semaphore to release its lock on the resource. This would be accomplished by calling semaphore.WaitOne() in the else block:</p>
<pre class="brush: csharp; title: ; notranslate">
    class Program
    {
        const string Id = &quot;af49d266-e4f4-4a63-b73c-f62c1144b584&quot;;
        static void Main(string[] args)
        {
            bool thisInstance;
            using (var semaphore = new Semaphore(0, 1, Id, out thisInstance))
            {
                if (thisInstance)
                {
                    Console.WriteLine(&quot;This is the first instance!&quot;);
                    Console.ReadLine();

                    // Release resource
                    semaphore.Release();
                }
                else
                {
                    Console.WriteLine(&quot;There is another instance running.&quot;);

                    // Wait for resource
                    semaphore.WaitOne();
                    Console.WriteLine(&quot;There is now the only instance.&quot;);
                    Console.ReadLine();
                }
            }
        }
    }
</pre>
<p>
<a href="http://www.ipreferjim.com/site/wp-content/uploads/2012/04/SingleInstance-queued.png?9d7bd4"><img src="http://www.ipreferjim.com/site/wp-content/uploads/2012/04/SingleInstance-queued-300x115.png?9d7bd4" alt="" title="SingleInstance-queued" width="300" height="115" class="aligncenter size-medium wp-image-848" /></a>
</p>
<p>Wait a second.  Didn't I say that wrapping the Semaphore object in a using block would call Close()?  Why did I have to explicitly call semaphore.Release()?</p>
<p>The answer to this is Garbage Collection.  Sure, Close() will be called (and thus, Release() is called and signals all waiting threads that the resource is available) when the using block exits, but this will only happen when the object is disposed. If you plan to queue up applications (or windows, dialogs, or any other resource), note this signaling behavior.</p>
<h2>Code</h2>
<p>I've decided to start making code from my blog posts available from a single github repository.</p>
<p><a href="https://github.com/jimschubert/blogs" title="https://github.com/jimschubert/blogs" target="_blank">https://github.com/jimschubert/blogs</a></p>
<h2>References</h2>
<ul>
<li><a href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD01xx/EWD123.html#4. The General Semaphore." title="The General Semaphore" target="_blank">The General Semaphore</a>, <a href="http://www.cs.utexas.edu/users/EWD/ewd01xx/EWD123.PDF" title="The General Semaphore (original)" target="_blank">original</a>
</li>
<li><a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms685129(v=vs.85).aspx" title="Semaphore Objects" target="_blank">Semaphore Objects</a></li>
</ul>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=840&amp;md5=355cbd8972faf0ea93c5269207106d28" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/3xBp4_yb-wavynjvPk_FSEeZyNI/0/da"><img src="http://feedads.g.doubleclick.net/~a/3xBp4_yb-wavynjvPk_FSEeZyNI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/3xBp4_yb-wavynjvPk_FSEeZyNI/1/da"><img src="http://feedads.g.doubleclick.net/~a/3xBp4_yb-wavynjvPk_FSEeZyNI/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/UBEdVuH-ZvU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/04/allowing-only-a-single-instance-of-a-net-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F04%2Fallowing-only-a-single-instance-of-a-net-application%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=Allowing+only+a+single+instance+of+a+.NET+application&amp;description=In+the+past%2C+whenever+I+constrained+an+application+to+having+only+a+single+instance+running+at+any+given+time%2C+I+naively+walked+a+list+of+running+processes+to+find+a...&amp;tags=Advanced%2CC%23%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/04/allowing-only-a-single-instance-of-a-net-application/</feedburner:origLink></item>
		<item>
		<title>C++ Global _CRT_SECURE_NO_WARNINGS</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/s0pOKxk6QxI/</link>
		<comments>http://www.ipreferjim.com/2012/04/c-global-_crt_secure_no_warnings/#comments</comments>
		<pubDate>Mon, 16 Apr 2012 20:43:09 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[msbuild]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=834</guid>
		<description><![CDATA[I became extremely annoyed by thousands of these messages while running MSBuild: I looked for the online help, which doesn't really exist for this specific warning. I did find the Security Features in the CRT article, but that was useless. Because I'm working on a shared project, I didn't want to manually add this #define [...]]]></description>
			<content:encoded><![CDATA[<p>I became extremely annoyed by thousands of these messages while running MSBuild:</p>
<pre class="brush: plain; title: ; notranslate">
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h(105) :
see declaration of 'strcpy' SomeFile.cpp(###):
warning C4996: 'strcpy': This function or variable may be unsafe.
Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
See online help for details.
</pre>
<p>I looked for the online help, which doesn't really exist for this specific warning. I did find the <a href="http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx" title="Security Features in the CRT" target="_blank">Security Features in the CRT</a> article, but that was useless.  Because I'm working on a shared project, I didn't want to manually add this #define to every project.  The workaround is to add it to the *.user.props file.</p>
<p>Add the <em>ItemDefinitionGroup</em> node below to <strong>C:\Users\Jschubert\AppData\Local\Microsoft\MSBuild\v4.0\Microsoft.Cpp.Win32.user.props</strong>:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;Project DefaultTargets=&quot;Build&quot; ToolsVersion=&quot;4.0&quot;
         xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&gt;
  &lt;ItemDefinitionGroup&gt;
    &lt;ClCompile&gt;
      &lt;PreprocessorDefinitions&gt;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)&lt;/PreprocessorDefinitions&gt;
    &lt;/ClCompile&gt;
    &lt;ResourceCompile&gt;
      &lt;PreprocessorDefinitions&gt;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)&lt;/PreprocessorDefinitions&gt;
    &lt;/ResourceCompile&gt;
  &lt;/ItemDefinitionGroup&gt;
&lt;/Project&gt;
</pre>
<p>And there you have thousands of annoying warnings disappear.  </p>
<p>Because MSBuild always includes <em>%(PreprocessorDefinitions)</em> when chaining PreprocessorDefinitions, you can add any number of defines here to exist globally on your machine only.</p>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=834&amp;md5=2efb45f20c927a08c38494800c0e686e" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/hYrRvse0sevZduXNvdNnH0fbt7w/0/da"><img src="http://feedads.g.doubleclick.net/~a/hYrRvse0sevZduXNvdNnH0fbt7w/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/hYrRvse0sevZduXNvdNnH0fbt7w/1/da"><img src="http://feedads.g.doubleclick.net/~a/hYrRvse0sevZduXNvdNnH0fbt7w/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/s0pOKxk6QxI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/04/c-global-_crt_secure_no_warnings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F04%2Fc-global-_crt_secure_no_warnings%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=C%2B%2B+Global+_CRT_SECURE_NO_WARNINGS&amp;description=I+became+extremely+annoyed+by+thousands+of+these+messages+while+running+MSBuild%3A+I+looked+for+the+online+help%2C+which+doesn%27t+really+exist+for+this+specific+warning.+I+did+find+the...&amp;tags=C%23%2Cmsbuild%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/04/c-global-_crt_secure_no_warnings/</feedburner:origLink></item>
		<item>
		<title>Ubuntu: Open With… Wireshark</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/vuQzG_cQRlg/</link>
		<comments>http://www.ipreferjim.com/2012/03/ubuntu-open-with-wireshark/#comments</comments>
		<pubDate>Fri, 23 Mar 2012 15:50:51 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=827</guid>
		<description><![CDATA[Reading through Practical Packet Analysis, I ran local captures to follow along until Chapter 5. Instead of trying to simulate an improperly-dissected packet, I downloaded the captures which accompany the book. In Ubuntu 11.10, I didn't see any way to easily associate .pcap files with Wireshark. In previous versions of Ubuntu, the 'add' button was [...]]]></description>
			<content:encoded><![CDATA[<p>Reading through <a href="http://nostarch.com/packet2.htm" title="Practical Packet Analysis, 2nd Edition" target="_blank">Practical Packet Analysis</a>, I ran local captures to follow along until Chapter 5. Instead of trying to simulate an improperly-dissected packet, I downloaded the captures which accompany the book. In Ubuntu 11.10, I didn't see any way to easily associate .pcap files with Wireshark.  In previous versions of Ubuntu, the 'add' button was available in the 'Open with...' dialog, but in 11.10 it is grayed out. Clicking the option to choose another application or find an available application online didn't work.  Bummer.</p>
<p>To get wireshark to show up in the 'Open With...' dialog's choice of applications, I followed the instructions on <a href="http://askubuntu.com/questions/72535/creating-desktop-files-to-use-on-the-open-with-other-application-tab" title="AskUbuntu.com" target="_blank">AskUbuntu.com</a>.  The instructions are for vim, so I've modified them for wireshark.</p>
<p>Save the following as <em>~/.local/share/applications/wireshark.desktop</em>:</p>
<pre class="brush: plain; title: ; notranslate">
[Desktop Entry]
Encoding=UTF-8
Name=Wireshark
Comment=Wireshark packet capturing
Exec=wireshark %u
Terminal=false
Type=Application
Icon=/usr/share/pixmaps/hi48-app-wireshark.png
Categories=Application;Utility;
StartupNotify=true
MimeType=application/octet-stream
NoDisplay=false
</pre>
<p>For more information about .desktop files, check out the <a href="http://www.nautilus-actions.org/?q=node/377" title="Desktop File Specification" target="_blank">Desktop File Specification</a>.</p>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=827&amp;md5=aa87a3357e05fbca1776b77960050574" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/UAp5l7bUb7NsRsqoPrHealdTC2s/0/da"><img src="http://feedads.g.doubleclick.net/~a/UAp5l7bUb7NsRsqoPrHealdTC2s/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/UAp5l7bUb7NsRsqoPrHealdTC2s/1/da"><img src="http://feedads.g.doubleclick.net/~a/UAp5l7bUb7NsRsqoPrHealdTC2s/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/vuQzG_cQRlg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/03/ubuntu-open-with-wireshark/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F03%2Fubuntu-open-with-wireshark%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=Ubuntu%3A+Open+With%26%238230%3B+Wireshark&amp;description=Reading+through+Practical+Packet+Analysis%2C+I+ran+local+captures+to+follow+along+until+Chapter+5.+Instead+of+trying+to+simulate+an+improperly-dissected+packet%2C+I+downloaded+the+captures+which+accompany+the...&amp;tags=linux%2CUbuntu%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/03/ubuntu-open-with-wireshark/</feedburner:origLink></item>
		<item>
		<title>C# Null-Coalescing (??) operator</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/uR8ulU7GMGo/</link>
		<comments>http://www.ipreferjim.com/2012/03/c-null-coalescing-operator/#comments</comments>
		<pubDate>Mon, 19 Mar 2012 01:39:38 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=819</guid>
		<description><![CDATA[The null-coalescing operator (??) is one of my favorites, and I see so few developers using it. MSDN defines the null-coalescing operator as The ?? operator is called the null-coalescing operator and is used to define a default value for nullable value types or reference types. It returns the left-hand operand if the operand is [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://msdn.microsoft.com/en-us/library/ms173224.aspx" title="?? Operator (C# Reference)" target="_blank">null-coalescing</a> operator (??) is one of my favorites, and I see so few developers using it.</p>
<p>MSDN defines the null-coalescing operator as</p>
<blockquote><p>
The ?? operator is called the null-coalescing operator and is used to define a default value for nullable value types or reference types. It returns the left-hand operand if the operand is not null; otherwise it returns the right operand.
</p></blockquote>
<p>Although this is somewhat similar to a <a href="http://msdn.microsoft.com/en-us/library/ty67wk28.aspx" title="?: Operator (C# Reference)" target="_blank">conditional operator</a> (sometimes called 'ternary operator'), it is much more concise.</p>
<p>The null-coalescing operator works with nullable value types and reference types. When I first started with the null-coalescing operator, I often underestimated the usage with empty strings. I think this is very important to discuss, hence this blog post.</p>
<h2>Strings</h2>
<p>For example:</p>
<pre class="brush: csharp; title: ; notranslate">
// conditional operator
string example = null;
string first = example == null ? &quot;default&quot; : example;

// null-coalescing operator
string second = example ?? &quot;default&quot;;
</pre>
<p>In both of these cases, the resulting string will be "default".</p>
<p>The problem with strings is that the null-coalescing operator only checks against <strong>nulls</strong>. Code may often return String.Empty instead of nulls.  Meaning the following example is not the same.</p>
<pre class="brush: csharp; title: ; notranslate">
// conditional operator
string example = string.Empty;
string first = string.IsNullOrEmpty(example) ? &quot;default&quot; : example;

// null-coalescing operator
string second = example ?? &quot;default&quot;;
</pre>
<p>In this example, 'first' will be "default" while 'second' will be the empty string. This is a situation in which the null-coalescing operator is useful only when a string must not be null but string.Empty is still perfectly valid.</p>
<h2>Nullable Value Types</h2>
<p>When working with nullable types, the conditional and null-coalescing operators have another alternative when retrieving the underlying value: <a href="http://msdn.microsoft.com/en-us/library/72cec0e0.aspx" title="Nullable&lt;T&gt;.GetValueOrDefault Method" target="_blank">GetValueOrDefault()</a>. The problem here is that the method returns the value type, not another nullable type.</p>
<p>For example:</p>
<pre class="brush: csharp; title: ; notranslate">
int? example = null;

// Conditional operator
int? first = example == null ? 100 : example;
int firstValue = first.Value;

// null-coalescing operator
int? second = example ?? 100;
int secondValue = second.Value;

// GetValueOrDefault()
int third = example.GetValueOrDefault(); // third = 0
int fourth = example.GetValueOrDefault(100); // fourth = 100
</pre>
<p>Notice the catch in the GetValueOrDefault() example... you don't have to reassign the nullable and then get the value. This is useful when you only need the value type.  Sometimes, you need a default value and the nullable type.  In these cases, I still prefer the null-coalescing operator.</p>
<h2>Reference types</h2>
<p>The null-coalescing operator can be used with reference types to guarantee that properties or methods do not return nulls.</p>
<p>For example:</p>
<pre class="brush: csharp; title: ; notranslate">
public List&lt;Person&gt; People
{
    get
    {
        return _people ?? new List&lt;Person&gt;();
    }
    set { /* something */ }
}
</pre>
<p>This is definitely a design/coding preference.  I've experienced  environments where developers insist on the importance of the NullReferenceException being thrown in production code. I've also experience plenty of environments where exceptional code is properly handled and this construct would rarely, if ever, be useful.</p>
<p>Maybe it is not a well-known operator, or most developers would like code to be lengthier and explicit. In a web development team, I think the null-coalescing operator is very similar to the common JavaScript example of providing a default value using the || operator:</p>
<pre class="brush: jscript; title: ; notranslate">
var process = function(val) {
    val = val || 100;
    /* etc. */
}
</pre>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=819&amp;md5=fda646fb0f996db3f1b1c4a9191f6d2e" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/ZE1bim9DzFLbw_Oi0LMUVzcdRsU/0/da"><img src="http://feedads.g.doubleclick.net/~a/ZE1bim9DzFLbw_Oi0LMUVzcdRsU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ZE1bim9DzFLbw_Oi0LMUVzcdRsU/1/da"><img src="http://feedads.g.doubleclick.net/~a/ZE1bim9DzFLbw_Oi0LMUVzcdRsU/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/uR8ulU7GMGo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/03/c-null-coalescing-operator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F03%2Fc-null-coalescing-operator%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=C%23+Null-Coalescing+%28%3F%3F%29+operator&amp;description=The+null-coalescing+operator+%28%3F%3F%29+is+one+of+my+favorites%2C+and+I+see+so+few+developers+using+it.+MSDN+defines+the+null-coalescing+operator+as+The+%3F%3F+operator+is+called+the+null-coalescing...&amp;tags=.NET%2CC%23%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/03/c-null-coalescing-operator/</feedburner:origLink></item>
		<item>
		<title>My Review of Accessible EPUB 3</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/g_BETnzBJH4/</link>
		<comments>http://www.ipreferjim.com/2012/02/my-review-of-accessible-epub-3/#comments</comments>
		<pubDate>Thu, 23 Feb 2012 02:16:54 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Review]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=815</guid>
		<description><![CDATA[Originally submitted at O'Reilly Best Practices for Creating Universally Usable Content Accessible EPUB 3 Good content about a new standard By Jim Schubert from Richmond, VA on 2/22/2012 &#160; 4out of 5 Pros: Accurate, Concise Cons: "however" Best Uses: Novice, Student Describe Yourself: Software Engineer I reviewed Accessible EPUB 3 as part of the O'Reilly [...]]]></description>
			<content:encoded><![CDATA[<div class="hreview">
<div class="item">
<p><a href="http://shop.oreilly.com/product/0636920025283.do">Originally submitted at O'Reilly</a></p>
<div><img src="http://images.powerreviews.com/images_products/05/49/15318982_100.jpg" class="photo" align="left" style="margin: 0 0.5em 0 0">
<p style="margin-top:0">Best Practices for Creating Universally Usable Content</p>
</div>
<p><a href="http://shop.oreilly.com/product/0636920025283.do" style="display: none;" class="url fn"><span class="fn">Accessible EPUB 3</span></a></div>
<p><br clear="left">
<p><strong class="summary">Good content about a new standard</strong></p>
<div>By <strong>Jim Schubert</strong> from <strong>Richmond, VA</strong> on <strong><abbr title="2012222T1200-0800" class="dtreviewed" style="border: none; text-decoration: none;">2/22/2012</abbr></strong></div>
<p>
<div style="margin: 0.5em 0; height: 15px; width: 83px; background-image: url(http://images.powerreviews.com/images/stars_small.gif); background-position: 0px -144px;" class="prStars prStarsSmall">&nbsp;</div>
</p>
<div style="display: none"><span class="rating">4</span>out of 5</div>
<p><strong>Pros: </strong>Accurate, Concise</p>
<p><strong>Cons: </strong>"however"</p>
<p><strong>Best Uses: </strong>Novice, Student</p>
<p><strong>Describe Yourself: </strong>Software Engineer</p>
<p style="margin-top:1em" class="description">I reviewed Accessible EPUB 3 as part of the O'Reilly Blogger program.  This book is actually an excerpt from the upcoming EPUB 3 Best Practices.<br xmlns:pr="xalan://com.pufferfish.core.beans.xmlbuilders.xsl.Functions"><br />The content of this excerpt is undeniably rich. The first 25 pages or so may be 'review' material if you're already pretty familiar with HTML5. If so, skim these pages for the EPUB-specific additions.</p>
<p>Knowing very little about the changes in EPUB 3, I was very intrigued by the audio and video capabilities that mirror those of HTML5. I would have liked to see more discussion about the support of these elements in readers on the market.  There were a few places where the author warned about new features not being fully available in many readers, but the lack of statistics made me wonder if this is merely speculation or if any readers currently support the new features.</p>
<p>I thought the Text-to-Speech section was very informative. The concept of having a lexicon as a pronunciation index coupled with inline SSML will make EPUB 3 very usable on readers. I sometimes turn on a screen reader just to see how elements are read aloud, laughing at mispronounced words or phrases. If authors and publishers put in the effort to add these features of EPUB 3, text-to-speech engines will make only a fraction of the pronunciation mistakes.</p>
<p>I would have given this excerpt five stars, but the language was occasionally difficult to read.  For instance, the author really enjoys ending sentences with "however" as if it is a filler word. After encountering this a few times, I ended up reading over sentences (sometimes spanning 2-3 lines of a paragraph) and replacing the ending "however" with synonyms to see if it made sense. Mostly, it didn't. I think this really detracted from the overall content, because I found myself retracing so much text to understand how the disjointed conjunctive adverb made sense that the content ended up feeling choppy.</p>
<p>Since the end result is still in production, I would imagine this text has already gone through a few rounds of editing.</p>
<p style="margin-top:0.5em">(<a href="http://www.powerreviews.com/legal/terms_of_use.html" rel="license">legalese</a>)</p>
</div>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=815&amp;md5=cb0121781d2060e7d7c915b07c197e31" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/ckafOXQJYCzsJceL_Zzsg93bdvM/0/da"><img src="http://feedads.g.doubleclick.net/~a/ckafOXQJYCzsJceL_Zzsg93bdvM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ckafOXQJYCzsJceL_Zzsg93bdvM/1/da"><img src="http://feedads.g.doubleclick.net/~a/ckafOXQJYCzsJceL_Zzsg93bdvM/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/g_BETnzBJH4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/02/my-review-of-accessible-epub-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F02%2Fmy-review-of-accessible-epub-3%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=My+Review+of+Accessible+EPUB+3&amp;description=Originally+submitted+at+O%27Reilly+Best+Practices+for+Creating+Universally+Usable+Content+Accessible+EPUB+3+Good+content+about+a+new+standard+By+Jim+Schubert+from+Richmond%2C+VA+on+2%2F22%2F2012+%26nbsp%3B+4out...&amp;tags=Review%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/02/my-review-of-accessible-epub-3/</feedburner:origLink></item>
		<item>
		<title>git push: fatal: unable to read SHA1</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/CZCVzYP0Y54/</link>
		<comments>http://www.ipreferjim.com/2012/02/git-push-fatal-unable-to-read-sha1/#comments</comments>
		<pubDate>Tue, 21 Feb 2012 01:46:00 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Errors]]></category>
		<category><![CDATA[github]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=808</guid>
		<description><![CDATA[Today, I was faced with an interesting error in a git repository. I am backing up a lot of old projects from during and after college into a private git repo. In doing so, I moved some folders around which disconnected a couple of binary files. After pushing, I received an error: unable to read [...]]]></description>
			<content:encoded><![CDATA[<p>Today, I was faced with an interesting error in a git repository.  I am backing up a lot of old projects from during and after college into a private git repo.  In doing so, I moved some folders around which disconnected a couple of binary files.  After pushing, I received an error: <strong>unable to read [SHA1]</strong>.</p>
<p>The fixes, in short:</p>
<pre class="brush: bash; title: ; notranslate">
$ git fsck
$ git log --raw --all --full-history | grep SHA1-HERE
$ git hash-object -w OBJECT-PATH-HERE
$ git push
</pre>
<p>Here is the error and a walk-through of coming up with the fixes above:</p>
<pre class="brush: bash; title: ; notranslate">
jim at schubert in /media/16GB/projects/school on master
$ git push
Password:
Counting objects: 1945, done.
error: unable to find 2978ec4d75abb8c6bab225d8adfbd2bef064338a
error: unable to unpack bddbd13afd698e5ba7d572c9270e52bcac862661 header
error: inflateEnd: failed
Delta compression using up to 2 threads.
Compressing objects: 100% (1854/1854), done.
fatal: unable to read 2978ec4d75abb8c6bab225d8adfbd2bef064338a
fatal: The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly
fatal: write error: Bad file descriptor
</pre>
<p>After running <em>git fsck</em>, I found that I had two missing blobs:</p>
<pre class="brush: bash; title: ; notranslate">
jim at schubert in /media/16GB/projects/school on master*
$ git fsck
dangling tree dbe9172996edbb7df517b0305c38891d78b72f66
dangling tree fbf7d8336b5f2347da23eb8a3938de5ab18f783c
missing blob 2978ec4d75abb8c6bab225d8adfbd2bef064338a
missing blob bddbd13afd698e5ba7d572c9270e52bcac862661
</pre>
<p>To fix this, I had to get the filenames of these blobs and write them back into the repository:</p>
<pre class="brush: bash; title: ; notranslate">
jim at schubert in /media/16GB/projects/school on master*
$ git log --raw --all --full-history | grep bddbd13
:000000 100644 0000000... bddbd13... A	INFO 465/Project2/UseCase/Diagrams/Leader - Time &amp; Mileage.vsd

jim at schubert in /media/16GB/projects/school on master*
$ git log --raw --all --full-history | grep 2978ec4
:000000 100644 0000000... 2978ec4... A	INFO 465/Project2/Prototype/WebPrototype/WebPrototype/bin/WebPrototype.dll
</pre>
<p>Writing these files back into the repository, the push was successful.  To write these back, do the following:</p>
<pre class="brush: bash; title: ; notranslate">
jim at schubert in /media/16GB/projects/school on master
$ git hash-object -w INFO\ 465/Project2/UseCase/Diagrams/Leader\ -\ Time\ \&amp;\ Mileage.vsd
bddbd13afd698e5ba7d572c9270e52bcac862661
jim at schubert in /media/16GB/projects/school on master
$ git hash-object -w INFO\ 465/Project2/Prototype/WebPrototype/WebPrototype/bin/WebPrototype.dll
2978ec4d75abb8c6bab225d8adfbd2bef064338a
</pre>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=808&amp;md5=9727c12eefecd3576868957e3dc63837" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/Kj37nR5VnvYHgC3bW6dFZiVUG4U/0/da"><img src="http://feedads.g.doubleclick.net/~a/Kj37nR5VnvYHgC3bW6dFZiVUG4U/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/Kj37nR5VnvYHgC3bW6dFZiVUG4U/1/da"><img src="http://feedads.g.doubleclick.net/~a/Kj37nR5VnvYHgC3bW6dFZiVUG4U/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/CZCVzYP0Y54" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/02/git-push-fatal-unable-to-read-sha1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F02%2Fgit-push-fatal-unable-to-read-sha1%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=git+push%3A+fatal%3A+unable+to+read+SHA1&amp;description=Today%2C+I+was+faced+with+an+interesting+error+in+a+git+repository.+I+am+backing+up+a+lot+of+old+projects+from+during+and+after+college+into+a+private+git...&amp;tags=Errors%2Cgithub%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/02/git-push-fatal-unable-to-read-sha1/</feedburner:origLink></item>
		<item>
		<title>My Review of Learning Perl, 5th Edition</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/RsPwTAO4O3A/</link>
		<comments>http://www.ipreferjim.com/2012/02/my-review-of-learning-perl-5th-edition/#comments</comments>
		<pubDate>Sat, 18 Feb 2012 22:00:33 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Review]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=805</guid>
		<description><![CDATA[Originally submitted at O'Reilly Making Easy Things Easy and Hard Things Possible Learning Perl, 5th Edition Great intro to Perl By Jim Schubert from Richmond, VA on 2/18/2012 &#160; 5out of 5 Pros: Helpful examples, Easy to understand, Concise, Well-written, Accurate Best Uses: Novice, Student Describe Yourself: Software Engineer I picked up this book on [...]]]></description>
			<content:encoded><![CDATA[<div class="hreview">
<div class="item">
<p><a href="http://oreilly.com/product/9780596520113.do">Originally submitted at O'Reilly</a></p>
<div><img src="http://images.powerreviews.com/images_products/06/14/5204063_100.jpg" class="photo" align="left" style="margin: 0 0.5em 0 0">
<p style="margin-top:0">Making Easy Things Easy and Hard Things Possible</p>
</div>
<p><a href="http://shop.oreilly.com/product/9780596520113.do" style="display: none;" class="url fn"><span class="fn">Learning Perl, 5th Edition</span></a></div>
<p><br clear="left">
<p><strong class="summary">Great intro to Perl</strong></p>
<div>By <strong>Jim Schubert</strong> from <strong>Richmond, VA</strong> on <strong><abbr title="2012218T1200-0800" class="dtreviewed" style="border: none; text-decoration: none;">2/18/2012</abbr></strong></div>
<p>
<div style="margin: 0.5em 0; height: 15px; width: 83px; background-image: url(http://images.powerreviews.com/images/stars_small.gif); background-position: 0px -180px;" class="prStars prStarsSmall">&nbsp;</div>
</p>
<div style="display: none"><span class="rating">5</span>out of 5</div>
<p><strong>Pros: </strong>Helpful examples, Easy to understand, Concise, Well-written, Accurate</p>
<p><strong>Best Uses: </strong>Novice, Student</p>
<p><strong>Describe Yourself: </strong>Software Engineer</p>
<p style="margin-top:1em" class="description">I picked up this book on a whim to learn Perl. I was extremely impressed, especially by the three chapters on Regular Expressions.<br xmlns:pr="xalan://com.pufferfish.core.beans.xmlbuilders.xsl.Functions"><br />If you have used Perl, this book may be fairly basic.  There are whole chapters on Scalars, Arrays, Hashes, etc. I have a lot of experience in a lot of languages and technologies, and I can tell you this book is well-written and well-organized to ease you into the Perl mindset.</p>
<p>First of all, most languages are like mathematics.  1+1=2 is a rule. If that rule didn't work, math wouldn't work.  Similarly, 'int x = 1;' in C-style languages will always point the variable 'x' to the memory location storing the value of '1'. Rules are rules.  However, Perl is contextual.  When you do one thing in Perl, you may have a different result depending on the context of the code.  For example (extremely-generalized example), hashes can be considered an array of values in which every even index is the key and every odd index is the value.  So, an array of ["first", "1st", "second", "2nd" ] could easily become a hash with the keys and values related as expected.  Weird? Yes. Basic, not really. I think that can be a very difficult concept for a lot of people... too meta.</p>
<p>The book does a great job of easing a lot of the Perl concepts onto the reader.  Interestingly, the part of the book I found the most useful are the three Regular Expressions chapters.  I have recommended this book to students in the past solely for the three Regular Expressions chapters.  They are clearly and concisely written in a way that presents the Perl syntax very well.</p>
<p>If you're familiar with Perl already, this book probably isn't for you.  You would probably be better off with the Intermediate Perl book also available by O'Reilly.  Even after reading both books and working a bit with the Catalyst framework, I found myself coming back to the last chapter of this book to fully understand eval blocks.</p>
<p style="margin-top:0.5em">(<a href="http://www.powerreviews.com/legal/terms_of_use.html" rel="license">legalese</a>)</p>
</div>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=805&amp;md5=68f26f34fc24dd906270edd61b46f50e" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/G0w7mbzbqSAIuWu_6WchDeGHOyY/0/da"><img src="http://feedads.g.doubleclick.net/~a/G0w7mbzbqSAIuWu_6WchDeGHOyY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/G0w7mbzbqSAIuWu_6WchDeGHOyY/1/da"><img src="http://feedads.g.doubleclick.net/~a/G0w7mbzbqSAIuWu_6WchDeGHOyY/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/RsPwTAO4O3A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/02/my-review-of-learning-perl-5th-edition/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F02%2Fmy-review-of-learning-perl-5th-edition%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=My+Review+of+Learning+Perl%2C+5th+Edition&amp;description=Originally+submitted+at+O%27Reilly+Making+Easy+Things+Easy+and+Hard+Things+Possible+Learning+Perl%2C+5th+Edition+Great+intro+to+Perl+By+Jim+Schubert+from+Richmond%2C+VA+on+2%2F18%2F2012+%26nbsp%3B+5out...&amp;tags=Review%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/02/my-review-of-learning-perl-5th-edition/</feedburner:origLink></item>
		<item>
		<title>My Review of CLR via C#, 3rd Edition</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/6-8YI3kNpH0/</link>
		<comments>http://www.ipreferjim.com/2012/02/my-review-of-clr-via-c-3rd-edition/#comments</comments>
		<pubDate>Sat, 18 Feb 2012 21:44:45 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Review]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=801</guid>
		<description><![CDATA[Originally submitted at O'Reilly CLR via C#, 3rd Edition CLR via C#, 3rd Edition One of the best C# books available. By Jim Schubert from Richmond, VA on 2/18/2012 &#160; 5out of 5 Pros: Helpful examples, Accurate, Concise, Easy to understand, Well-written Best Uses: Expert, Intermediate, Student Describe Yourself: Software Engineer It has been a [...]]]></description>
			<content:encoded><![CDATA[<div class="hreview">
<div class="item">
<p><a href="http://oreilly.com/catalog/9780735627048">Originally submitted at O'Reilly</a></p>
<div><img src="http://images.powerreviews.com/images_products/00/88/7284232_100.jpg" class="photo" align="left" style="margin: 0 0.5em 0 0">
<p style="margin-top:0">CLR via C#, 3rd Edition</p>
</div>
<p><a href="http://oreilly.com/catalog/9780735627048" style="display: none;" class="url fn"><span class="fn">CLR via C#, 3rd Edition</span></a></div>
<p><br clear="left">
<p><strong class="summary">One of the best C# books available.</strong></p>
<div>By <strong>Jim Schubert</strong> from <strong>Richmond, VA</strong> on <strong><abbr title="2012218T1200-0800" class="dtreviewed" style="border: none; text-decoration: none;">2/18/2012</abbr></strong></div>
<p>
<div style="margin: 0.5em 0; height: 15px; width: 83px; background-image: url(http://images.powerreviews.com/images/stars_small.gif); background-position: 0px -180px;" class="prStars prStarsSmall">&nbsp;</div>
</p>
<div style="display: none"><span class="rating">5</span>out of 5</div>
<p><strong>Pros: </strong>Helpful examples, Accurate, Concise, Easy to understand, Well-written</p>
<p><strong>Best Uses: </strong>Expert, Intermediate, Student</p>
<p><strong>Describe Yourself: </strong>Software Engineer</p>
<p style="margin-top:1em" class="description">It has been a while since I read this book.  I never reviewed it because I didn't realize Microsoft Press was sold on the O'Reilly site.<br xmlns:pr="xalan://com.pufferfish.core.beans.xmlbuilders.xsl.Functions"><br />I can not tell you how many times I have been asked an interview question which I answered quickly and concisely thanks to this book.  It covers a lot of material.  When I say "a lot", I don't mean the average amount of material in a book this length, I mean the average amount of material in a book that is three times the size of this book.  Seriously, it goes over some topics that other books don't touch on: like why strings are interned the way they are, string comparison optimizations, globalization gotchas, assembly structure, and a lot more.</p>
<p>I recommended this book to a friend a few days ago.  I would gladly recommend it to anyone who is a professional .NET developer or a student using .NET technologies. It thoroughly discusses the how, why, and when the CLR performs the way it does.</p>
<p>A note for beginners: I think this book is geared more toward intermediate-to-advanced developers.  If you find some of the content too difficult, skim it and come back to it later. You won't be let down.</p>
<p style="margin-top:0.5em">(<a href="http://www.powerreviews.com/legal/terms_of_use.html" rel="license">legalese</a>)</p>
</div>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=801&amp;md5=448dfe72e4052058503f653abd163a39" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/uQOa09FbBMfai6YPTIT-b3lV--g/0/da"><img src="http://feedads.g.doubleclick.net/~a/uQOa09FbBMfai6YPTIT-b3lV--g/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/uQOa09FbBMfai6YPTIT-b3lV--g/1/da"><img src="http://feedads.g.doubleclick.net/~a/uQOa09FbBMfai6YPTIT-b3lV--g/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/6-8YI3kNpH0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/02/my-review-of-clr-via-c-3rd-edition/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F02%2Fmy-review-of-clr-via-c-3rd-edition%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=My+Review+of+CLR+via+C%23%2C+3rd+Edition&amp;description=Originally+submitted+at+O%27Reilly+CLR+via+C%23%2C+3rd+Edition+CLR+via+C%23%2C+3rd+Edition+One+of+the+best+C%23+books+available.+By+Jim+Schubert+from+Richmond%2C+VA+on+2%2F18%2F2012+%26nbsp%3B...&amp;tags=Review%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/02/my-review-of-clr-via-c-3rd-edition/</feedburner:origLink></item>
		<item>
		<title>My Review of Node for Front-End Developers</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/EXvI_cu--Wk/</link>
		<comments>http://www.ipreferjim.com/2012/02/my-review-of-node-for-front-end-developers/#comments</comments>
		<pubDate>Sat, 11 Feb 2012 18:00:54 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Review]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=788</guid>
		<description><![CDATA[Originally submitted at O'Reilly Writing Server-Side JavaScript Applications Node for Front-End Developers Or... Prototyping with Node.js By Jim Schubert from Richmond, VA on 2/11/2012 &#160; 4out of 5 Pros: Well-written, Easy to understand, Concise, Accurate, Helpful examples Cons: Too short Best Uses: Student, Novice Describe Yourself: Software Engineer I've reviewed "Node for Front-End Developers" for [...]]]></description>
			<content:encoded><![CDATA[<div class="hreview">
<div class="item">
<p><a href="http://shop.oreilly.com/product/0636920023258.do">Originally submitted at O'Reilly</a></p>
<div><img src="http://images.powerreviews.com/images_products/05/49/14267351_100.jpg" class="photo" align="left" style="margin: 0 0.5em 0 0">
<p style="margin-top:0">Writing Server-Side JavaScript Applications</p>
</div>
<p><a href="http://shop.oreilly.com/product/0636920023258.do" style="display: none;" class="url fn"><span class="fn">Node for Front-End Developers</span></a></div>
<p><br clear="left">
<p><strong class="summary">Or... Prototyping with Node.js</strong></p>
<div>By <strong>Jim Schubert</strong> from <strong>Richmond, VA</strong> on <strong><abbr title="2012211T1200-0800" class="dtreviewed" style="border: none; text-decoration: none;">2/11/2012</abbr></strong></div>
<p>
<div style="margin: 0.5em 0; height: 15px; width: 83px; background-image: url(http://images.powerreviews.com/images/stars_small.gif); background-position: 0px -144px;" class="prStars prStarsSmall">&nbsp;</div>
</p>
<div style="display: none"><span class="rating">4</span>out of 5</div>
<p><strong>Pros: </strong>Well-written, Easy to understand, Concise, Accurate, Helpful examples</p>
<p><strong>Cons: </strong>Too short</p>
<p><strong>Best Uses: </strong>Student, Novice</p>
<p><strong>Describe Yourself: </strong>Software Engineer</p>
<p style="margin-top:1em" class="description">I've reviewed "Node for Front-End Developers" for the O'Reilly blogger program.  Because I've been contributing to an open-source Node.js ebook, I was very excited to read this book. I must warn you-- this book is less about Node.js than it is about prototyping web applications using modules available in Node.js.  If you begin reading this from that perspective and you have little knowledge of Node.js in general, you will gain a lot from reading this.  If, however, you have experience with Node.js and have used frameworks such as Express and Connect, there is not much more covered in these 58 pages.<br xmlns:pr="xalan://com.pufferfish.core.beans.xmlbuilders.xsl.Functions"><br />Garann Means has written this book in a great way.  She doesn't start off explaining the Express framework like most introductions to Node.js would have done. Instead, she shows how to create a minimal http server, add templating and middleware, and then discusses Express and separating concerns into an MVC or MVC-like pattern.  </p>
<p>There are a few times where I think the terminology could be misleading.  For example, at the beginning she talks about 'scaffolding'. Scaffolding in general implies code generation and the only bit of true scaffolding discussed in the book occurs on one line in one of the last few chapters when the Express framework generates an empty application.  I would have liked to see some true 'scaffolding' examples, either with code specific to the book or with third-party modules.  Aside from one or two other terminology issues (which is probably just me being picky), the content is spot-on.  </p>
<p>Garann does talk about asynchronous operations a little, but this is a huge area of concern for front-end and back-end developers when migrating to Node.js because the asynchronous and event-driven nature of common tasks (files, database) can often increase the complexity of a simple task.  Had she expanded on the asynchronous nature of Node.js more, I would have given this book five stars. She does offer a caveat in the Postscript that this book doesn't cover all there is to know about Node.js, and she's right. Before or after reading this, you should read the introduction in the Node.js documentation and the Express framework's documentation.  </p>
<p>In conclusion, this is an excellent introduction to prototyping web applications using Node.js. I would recommend this book to people who are familiar with JavaScript programming and want to being prototyping without the need to learn additional languages and frameworks like Ruby on Rails, Catalyst, ASP.NET MVC, etc.</p>
<p style="margin-top:0.5em">(<a href="http://www.powerreviews.com/legal/terms_of_use.html" rel="license">legalese</a>)</p>
</div>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=788&amp;md5=f85e651b695e773466f4319b4e668c85" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/jV0jlMc3gG1d2yaURJLwTV3dF3k/0/da"><img src="http://feedads.g.doubleclick.net/~a/jV0jlMc3gG1d2yaURJLwTV3dF3k/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/jV0jlMc3gG1d2yaURJLwTV3dF3k/1/da"><img src="http://feedads.g.doubleclick.net/~a/jV0jlMc3gG1d2yaURJLwTV3dF3k/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/EXvI_cu--Wk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/02/my-review-of-node-for-front-end-developers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F02%2Fmy-review-of-node-for-front-end-developers%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=My+Review+of+Node+for+Front-End+Developers&amp;description=Originally+submitted+at+O%27Reilly+Writing+Server-Side+JavaScript+Applications+Node+for+Front-End+Developers+Or...+Prototyping+with+Node.js+By+Jim+Schubert+from+Richmond%2C+VA+on+2%2F11%2F2012+%26nbsp%3B+4out+of+5+Pros%3A+Well-written%2C...&amp;tags=Review%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/02/my-review-of-node-for-front-end-developers/</feedburner:origLink></item>
		<item>
		<title>My Review of McCullough and Berglund on Mastering Advanced Git</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/X_vBcscATrk/</link>
		<comments>http://www.ipreferjim.com/2012/02/my-review-of-mccullough-and-berglund-on-mastering-advanced-git/#comments</comments>
		<pubDate>Tue, 07 Feb 2012 03:34:32 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=786</guid>
		<description><![CDATA[Originally submitted at O'Reilly McCullough and Berglund on Mastering Advanced Git McCullough and Berglund on Mastering Advanced Git Great demonstration of advanced Git By Jim Schubert from Richmond, VA on 2/6/2012 &#160; 5out of 5 Pros: Accurate, Easy to understand, Concise, Helpful examples Best Uses: Novice, Student, Expert, Intermediate Describe Yourself: Sys Admin, Maker, Developer, [...]]]></description>
			<content:encoded><![CDATA[<div class="hreview">
<div class="item">
<p><a href="http://oreilly.com/product/0636920024774.do">Originally submitted at O'Reilly</a></p>
<div><img src="http://images.powerreviews.com/images_products/01/34/15258733_100.jpg" class="photo" align="left" style="margin: 0 0.5em 0 0">
<p style="margin-top:0">McCullough and Berglund on Mastering Advanced Git</p>
</div>
<p><a href="http://shop.oreilly.com/product/0636920024774.do" style="display: none;" class="url fn"><span class="fn">McCullough and Berglund on Mastering Advanced Git</span></a></div>
<p><br clear="left">
<p><strong class="summary">Great demonstration of advanced Git</strong></p>
<div>By <strong>Jim Schubert</strong> from <strong>Richmond, VA</strong> on <strong><abbr title="201226T1200-0800" class="dtreviewed" style="border: none; text-decoration: none;">2/6/2012</abbr></strong></div>
<p>
<div style="margin: 0.5em 0; height: 15px; width: 83px; background-image: url(http://images.powerreviews.com/images/stars_small.gif); background-position: 0px -180px;" class="prStars prStarsSmall">&nbsp;</div>
</p>
<div style="display: none"><span class="rating">5</span>out of 5</div>
<p><strong>Pros: </strong>Accurate, Easy to understand, Concise, Helpful examples</p>
<p><strong>Best Uses: </strong>Novice, Student, Expert, Intermediate</p>
<p><strong>Describe Yourself: </strong>Sys Admin, Maker, Developer, Educator, Designer</p>
<p style="margin-top:1em" class="description">At just under 4 hours long, this video course packs in a lot of content. Each video is about 30 minutes long, so I didn't have to watch it all in one sitting.<br xmlns:pr="xalan://com.pufferfish.core.beans.xmlbuilders.xsl.Functions"><br />The structure of the demonstration is extremely useful because Tim and Matthew ask and answer questions conversationally while showing a split-view Git workspace. I think the hardest thing for some people to grasp in general about git is what 'distributed' means.  Although the presenters are working from the same machine, the setup is done in a way to demonstrate this distributed nature.</p>
<p>I've been using git for a while, but I have learned a lot from these videos. I've only somewhat dug into the files inside the .git directory on my own because I was afraid to 'ruin' my repository. This course does a great job of alleviating  a lot of those concerns by explaining the organizational structure of the .git contents.</p>
<p>If you're like me, you'll probably add quite a few of the concepts you learn from these videos to your repositories immediately after each video.</p>
<p style="margin-top:0.5em">(<a href="http://www.powerreviews.com/legal/terms_of_use.html" rel="license">legalese</a>)</p>
</div>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=786&amp;md5=a17ff03f614495092c2d9ff9d98d5830" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/nI1q-1oaGxNu62PqYvP-VerA5QE/0/da"><img src="http://feedads.g.doubleclick.net/~a/nI1q-1oaGxNu62PqYvP-VerA5QE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/nI1q-1oaGxNu62PqYvP-VerA5QE/1/da"><img src="http://feedads.g.doubleclick.net/~a/nI1q-1oaGxNu62PqYvP-VerA5QE/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/X_vBcscATrk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/02/my-review-of-mccullough-and-berglund-on-mastering-advanced-git/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F02%2Fmy-review-of-mccullough-and-berglund-on-mastering-advanced-git%2F&amp;hidden=true&amp;language=en_GB&amp;category=text&amp;title=My+Review+of+McCullough+and+Berglund+on+Mastering+Advanced+Git&amp;description=Originally+submitted+at+O%27Reilly+McCullough+and+Berglund+on+Mastering+Advanced+Git+McCullough+and+Berglund+on+Mastering+Advanced+Git+Great+demonstration+of+advanced+Git+By+Jim+Schubert+from+Richmond%2C+VA+on...&amp;tags=blog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/02/my-review-of-mccullough-and-berglund-on-mastering-advanced-git/</feedburner:origLink></item>
		<item>
		<title>Mastering Node: Addons and FunctionTemplate (uuid.node)</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/iXantxfyRJs/</link>
		<comments>http://www.ipreferjim.com/2012/02/mastering-node-addons-and-functiontemplate-uuid-node/#comments</comments>
		<pubDate>Tue, 07 Feb 2012 02:41:18 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Advanced]]></category>
		<category><![CDATA[eBooks]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[nodejs]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=769</guid>
		<description><![CDATA[Last night, I pushed an addition to my fork of Mastering Node. I decided to add a bit to the Addons chapter. The first example in this chapter only shows how to add a function to a natively-compiled module (i.e. an addon). This example shows you how to start a module which can be used [...]]]></description>
			<content:encoded><![CDATA[<p>Last night, I pushed an addition to my fork of Mastering Node. I decided to add a bit to the <em>Addons</em> chapter.  The first example in this chapter only shows how to add a function to a natively-compiled module (i.e. an addon).  This example shows you how to start a module which can be used in the following way:</p>
<pre class="brush: jscript; title: ; notranslate">
var Uuid = require('./uuid.node').Uuid;
var uuid = new Uuid();
var myId = uuid.generate();
</pre>
<p>The project files referenced in the following text can be downloaded from the repo: <a href="https://github.com/jimschubert/masteringnode" title="jimschubert/masteringnode" target="_blank">jimschubert/masteringnode</a></p>
<hr />
<h2 id="functionTemplate">FunctionTemplate</h2>
<p>In v8, a FunctionTemplate is used to create the equivalent to:</p>
<pre class="brush: jscript; title: ; notranslate">var template = function() { }</pre>
<p>The function at this point is an object and not an <em>instance</em> of the function. </p>
<p>As an example, we will use the linux package <em>uuid</em> to generate a uuid. We will define the header for this addon as:</p>
<p><span id="more-769"></span></p>
<pre class="brush: cpp; title: ; notranslate">
// addons/uuid/v0.1/uuid.h
#ifndef __node_uuid_h__
#define __node_uuid_h__

#include &lt;string&gt;
#include &lt;v8.h&gt;
#include &lt;node.h&gt;
#include &quot;uuid/uuid.h&quot;

using namespace v8;
using namespace node;

class Uuid : public node::ObjectWrap {
    public:
        Uuid() { }
        static Persistent&lt;FunctionTemplate&gt; constructor;
        static void Init(Handle&lt;Object&gt; target);
        static Handle&lt;Value&gt; New(const Arguments &amp;args);
        static Handle&lt;Value&gt; Generate(const Arguments &amp;args);
        static Handle&lt;Value&gt; GenerateRandom(const Arguments &amp;args);
        static Handle&lt;Value&gt; GenerateTime(const Arguments &amp;args);
    private:
        ~Uuid();
        static std::string GetString(uuid_t id);
};

#endif // __node_uuid_h__
</pre>
<p>This addon will showcase three methods, <code>Generate</code>, <code>GenerateRandom</code>, and <code>GenerateTime</code>. It will also include a trivial private <code>GetString</code> method to demonstrate how to <em>Unwrap</em> a <code>node::ObjectWrap</code> object and interact with C++ code that is not specific to node or v8.</p>
<p>A lot of the public function definitions should look similar to the <em>Echo</em> example. One notable difference is that instead of using a macro and hiding the <code>FunctionTemplate</code> method, we are defining <code>static Persistent<FunctionTemplate> constructor;</code>.  The <code>Persistent<T></code> type is used "when you need to keep a reference to an object for more than one function call, or when handle lifetimes do not correspond to C++ scopes." <a href="http://code.google.com/apis/v8/embed.html">source</a>.  Since we'd expect our object's constructor to last longer than a single function, we declare it separately and as a persistent handle.  Another point to notice is that all of the method we're pulling from <em>uuid.h</em> have the signature <code>static Handle<Value> Method(const Arguments &amp;args)</code> even though we will plan to call it as <code>uuid.generate()</code>.  This is because we will be accessing the <em>scope</em> of the call via <code>args.This()</code>.</p>
<p>Although more methods are implemented in <em>uuid.cc</em>, we will look at three:  </p>
<pre class="brush: cpp; light: true; title: ; notranslate">
Uuid::Init(Handle&lt;Object&gt; target)
Handle&lt;Value&gt; Uuid::New(const Arguments &amp;args)
Handle&lt;Value&gt; Uuid::Generate(const Arguments &amp;args)
</pre>
<p>Just as before, node expects to find a signature of <code>extern "C" void init(Handle&lt;Object> target)</code> in order to initialize the addon.  Inside this method, we may set parameters such as the version number from the previous example.  We may also pass-through initialization to any modules within our node addon.  In this example, our addon will be <em>uuid.node</em> and contain a single module, <em>Uuid</em>. There is no reason we can't later add <em>Uuid2</em> which, instead of returning a normalized string value might return a <code>Buffer</code> object.  To initialize the Uuid module, we pass the <code>target</code> object along to <code>Uuid::Init</code> and add the module definition to <code>target</code>:</p>
<pre class="brush: cpp; title: ; notranslate">
// addons/uuid/v0.1/uuid.cc
void Uuid::Init(Handle&lt;Object&gt; target) {
    HandleScope scope;

    // Setup the constructor
    constructor = Persistent&lt;FunctionTemplate&gt;::New(FunctionTemplate::New(Uuid::New));
    constructor-&gt;InstanceTemplate()-&gt;SetInternalFieldCount(1); // for constructors
    constructor-&gt;SetClassName(String::NewSymbol(&quot;Uuid&quot;));

    // Setup the prototype
    NODE_SET_PROTOTYPE_METHOD(constructor, &quot;generate&quot;, Generate);
    NODE_SET_PROTOTYPE_METHOD(constructor, &quot;generateRandom&quot;, GenerateRandom);
    NODE_SET_PROTOTYPE_METHOD(constructor, &quot;generateTime&quot;, GenerateTime);

    target-&gt;Set(String::NewSymbol(&quot;Uuid&quot;), constructor-&gt;GetFunction());
}
</pre>
<p>In this scope, we are instantiating the <code>constructor</code> using <code>Uuid::New</code> as a new <code>FunctionTemplate</code>. We then call <code>InstanceTemplate()</code> and on that object we call <code>SetInternalFieldCount(1)</code>. This tells v8 that this object holds a reference to one object.</p>
<p>Next, we setup the prototype using another macro provided by node. These calls say, for instance, "Add a method called <em>generate</em> to the constructor function which executes the native method <em>Generate</em>".</p>
<p>Lastly, we have to create a "Uuid" module on the object returned by the call to <code>require()</code>. Here, <code>Uuid</code> will point to a function (<code>constructor</code>) which returns a function that internally executes <code>Uuid::New</code>.  In other words, we have created something akin to: </p>
<pre class="brush: jscript; title: ; notranslate">
var Uuid = function() { };
Uuid.constructor = function() {
    return function() {
        // Uuid::New executes here.
    }
}
</pre>
<p>Although the above is not exactly what we have done, it may provide a better view for some to understand <code>FunctionTemplate</code> references and why we assign one to the constructor object in such a way.</p>
<p>The <code>Uuid::New</code> method is defined as:</p>
<pre class="brush: cpp; title: ; notranslate">
// addons/uuid/v0.1/uuid.cc
Handle&lt;Value&gt; Uuid::New(const Arguments &amp;amp;args) {
    HandleScope scope;
    // no args are checked
    Uuid *uuid = new Uuid();
    uuid-&gt;Wrap(args.This());
    return args.This();
}
</pre>
<p>As you would expect, calling the constructor function multiple times will create newly-scoped <code>Uuid</code> objects on the heap. In this method, we <a href="https://github.com/joyent/node/blob/v0.4.8/src/node_object_wrap.h#L59">wrap</a> the parameter (scoped object) by setting a reference to <code>Uuid</code> in the args as a contextual scope (i.e. <code>this</code>) and then returns <code>this</code>.</p>
<p>Within the <code>Generate</code> method, we will want to unwrap the contextual <code>Uuid</code> object and call the private method <code>GetString</code>.</p>
<pre class="brush: cpp; title: ; notranslate">
// addons/uuid/v0.1/uuid.cc
Handle&lt;Value&gt; Uuid::Generate(const Arguments &amp;amp;args) {
    HandleScope scope;
    uuid_t id;
    uuid_generate(id);

    Uuid *uuid = ObjectWrap::Unwrap&lt;Uuid&gt;(args.This());
    return scope.Close(String::New(uuid-&gt;GetString(id).c_str()));
}
</pre>
<p>As with any JavaScript function call, we have to ensure <a href="https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope">functional scope</a>. Scoped methods should create a <a href="http://code.google.com/apis/v8/embed.html">HandleScope</a> object at the start and call <code>scope.Close()</code> at the end. <code>HandleScope</code> will get rid of temporary handles when the scope is closed.</p>
<p>Within each of the <em>Generate*</em> methods, we will create a <code>uuid_t</code> type and call the corresponding method defined in <em>/usr/includes/uuid/uuid.h</em> (location may vary per system). To demonstrate accessing the pointer to our original <code>Uuid</code> object, we unwrap the contextual scope of this function using <code>ObjectWrap::Unwrap<Uuid>(args.This())</code>. From this pointer, we can access any private methods such as <code>GetString</code>. Be careful with your returned values, though. <code>String::New</code> in the v8 library does not take <code>std::string</code> in any of its signatures. Simply enough, <code>std::string</code> provides a <code>c_str()</code> method to return a <code>const char*</code> which <code>String::New</code> does accept.</p>
<h3 id="uuid.node_demo">uuid.node demo</h3>
<p>Navigate to <em>addons/uuid/v0.1/</em> and execute:</p>
<pre class="brush: bash; title: ; notranslate">
$ node-waf configure build
</pre>
<p>If there are build errors and the <em>func.cc</em> example from before built successfully, check that you have the <em>uuid-dev</em> package installed and rerun the above command. Then, navigate to <em>build/default</em> and try out the Uuid addon:</p>
<pre class="brush: bash; title: ; notranslate">
$ node
&gt; var Uuid = require('./uuid.node').Uuid;
&gt; var uuid = new Uuid();
&gt; uuid.generate();
'83475e0c-212b-402c-bdc7-b81ebb7b34f8'
&gt; uuid.generateRandom();
'4d597bda-8f5f-4c3c-b2fa-1cd6cd4a6903'
&gt; uuid.generateTime();
'25a0dd30-5076-11e1-96be-0022fb93b24c'
&gt; var util = require('util');
&gt; util.inspect(uuid);
'{}'
&gt; util.inspect(Uuid);
'[Function: Uuid]'
&gt;
</pre>
<p>The above output may surprise you. Firstly, where is the <code>version</code> option?! It's at the required module level: <code>require('./uuid.node').version;</code>. Secondly, if we can access <code>uuid.generate()</code> and others, why don't they display when inspecting the object? That's because we defined those methods on the prototype:</p>
<pre class="brush: jscript; title: ; notranslate">
&gt; uuid.__proto__
{ generate: [Function: generate],
  generateRandom: [Function: generateRandom],
  generateTime: [Function: generateTime] }
&gt;
</pre>
<p>Thirdly, you may have noticed that I didn't say anything about <code>constructor-&gt;SetClassName(String::NewSymbol("Uuid"));</code> in <code>Uuid::Init</code>. You may have also wondered where <code>SetClassName</code> actually sets a class name, considering JavaScript is a prototypal language. That string value is what is displayed when you call inspect and get the value <code>'[Function: Uuid]'</code>. Just as you would expect, <code>Uuid</code> is the constructor and it is named <code>Uuid</code>. </p>
<p>Now, if you've played around with this a bit, you may have noticed that <code>uuid.__proto__</code> gives us our three functions but <code>uuid.prototype</code> is empty. Why is that? That's because <code>uuid.__proto__</code> really is <code>uuid.constructor.prototype</code>, which is also really <code>Uuid.prototype</code>. This is the essence of prototypal inheritance. If this concept is foreign or difficult to grasp, be sure to check out the excellent explanation on <a href="http://bonsaiden.github.com/JavaScript-Garden/#object.prototype">JavaScript Garden</a>.</p>
<p>Logically, the next step would be to understand how to declare a prototype of our own.</p>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=769&amp;md5=c592d30e215e4fe6069edb8703a08bcf" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/mBN9jmWTAm-fLaUrbmxaYeE-d7U/0/da"><img src="http://feedads.g.doubleclick.net/~a/mBN9jmWTAm-fLaUrbmxaYeE-d7U/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/mBN9jmWTAm-fLaUrbmxaYeE-d7U/1/da"><img src="http://feedads.g.doubleclick.net/~a/mBN9jmWTAm-fLaUrbmxaYeE-d7U/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/iXantxfyRJs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/02/mastering-node-addons-and-functiontemplate-uuid-node/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F02%2Fmastering-node-addons-and-functiontemplate-uuid-node%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=Mastering+Node%3A+Addons+and+FunctionTemplate+%28uuid.node%29&amp;description=Last+night%2C+I+pushed+an+addition+to+my+fork+of+Mastering+Node.+I+decided+to+add+a+bit+to+the+Addons+chapter.+The+first+example+in+this+chapter+only+shows...&amp;tags=Advanced%2CeBooks%2Cgithub%2Cnodejs%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/02/mastering-node-addons-and-functiontemplate-uuid-node/</feedburner:origLink></item>
		<item>
		<title>words.pl: slogan word generator</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/zQ0CWLeoz4s/</link>
		<comments>http://www.ipreferjim.com/2012/02/words-pl-slogan-word-generator/#comments</comments>
		<pubDate>Sat, 04 Feb 2012 00:20:04 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[perl]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=762</guid>
		<description><![CDATA[About a year ago, I was really into playing this game online where you were given a single sentence and you had to use the letters in that sentence to make up as many words as possible. The longer the word, the higher the points. Creating a script may be considered cheating if you're in [...]]]></description>
			<content:encoded><![CDATA[<p>About a year ago, I was really into playing this game online where you were given a single sentence and you had to use the letters in that sentence to make up as many words as possible.  The longer the word, the higher the points.</p>
<p>Creating a script <em>may</em> be considered cheating if you're in it for money.  If you're in it for fun, script away.  That's what I always say.</p>
<p>Here's the gist of it:<br />
<script src="https://gist.github.com/1733871.js"> </script></p>
<pre class="brush: perl; collapse: true; light: false; title: ; toolbar: true; notranslate">
#!/usr/bin/env perl
# words.pl: Find all possible slogan words from a single sentence.
use strict; $|++;

@ARGV == 2 or die &quot;usage: $0 input_file output_file 'sentence'\n&quot;;
my ($infile, $outfile, $sentence) = @ARGV;
$sentence = $sentence || 'how much wood could a woodchuck chuck';

open INPUT, &quot;&lt; $infile&quot; or die $!;
open OUTPUT, &quot;&gt; $outfile&quot; or die $!;

my $stdout = select STDOUT;
$| = 1;
select $stdout;

my %sentence_letters;
my $stmp = $sentence;
$sentence_letters{$&amp;}++ while($stmp =~ s/[a-z]//);

print &quot;Using the sentence '$sentence'\n&quot;;
print &quot;Found the following letters:\n&quot;;
print &quot;\t$_ - &quot;. $sentence_letters{$_} .&quot;\n&quot; foreach(sort(keys %sentence_letters));
print &quot;Processing $infile for slogan words\n&quot;;

my $count = 0;
my @indicators = qw{\ / | .};
LINE: while(&lt;INPUT&gt;) {
    my $word = $_;
    my $tmp = $word;
    next LINE if($word =~ /['\&amp;\d]/);
    my %word_letters;
    $word_letters{$&amp;}++ while($tmp =~ s/[a-z]//);

    foreach(keys %word_letters) {
        next LINE if ($word_letters{$_} &gt; $sentence_letters{$_});
    }
    print OUTPUT $word;

    my $word_len = length($word);
    open WORD_LEN_OUTPUT, &quot;&gt;&gt; $outfile.$word_len&quot;;
    print WORD_LEN_OUTPUT $word;

    print $indicators[++$count % 4], &quot;\r&quot;;
}

print &quot;\nDone.\nView $outfile.* for words\n&quot;;
</pre>
<p>When I wrote this, I had only recently started using Perl.  Please go easy on me if it's poorly written.</p>
<p>The script takes an input file, an output file format (e.g. words.txt will be words.txt.20 for words of 20 characters), and an optional sentence to parse.</p>
<p>It gets a set of letters in the sentence, then runs through the list of words to see if the word can be made from any combination of letters.</p>
<p>For instance, if your 'sentence' is "baby cakes", the script will create a hash of those letters and their counts.  Conceptually, this looks like:</p>
<pre class="brush: jscript; title: ; notranslate">
// hash is an array
hash['a'] = 2
hash['b'] = 2
hash['c'] = 1
hash['e'] = 1
hash['k'] = 1
hash['s'] = 1
hash['y'] = 1
</pre>
<p>If, while walking line-by-line through your list of words, the script sees 'abracadabra', the loop will return false because (conceptually):</p>
<pre class="brush: jscript; title: ; notranslate">
word['a'] = 5
word['a'] &lt;= hash['a'] == false
</pre>
<p>The script also employs some interesting stdout manipulation. This allows the script to output "spinner text" and update the current line when the terminating character is a line-feed.</p>
<p>To run the script in a linux-based environment, you may do:</p>
<pre class="brush: bash; title: ; notranslate">
mkdir ~/projects &amp;&amp; cd ~/projects
git clone git://gist.github.com/1733871.git gist-1733871
cd gist-gist-1733871
perl words.pl /usr/share/dict/words generated.txt 'Good goly, Miss Molly'
</pre>
<p>You should see output similar to:</p>
<pre class="brush: bash; title: ; notranslate">

jim at schubert in ~/projects/gist-1733871 on master*
$ tree .
.
├── generated.txt
├── generated.txt.1
├── generated.txt.2
├── generated.txt.3
├── generated.txt.4
├── generated.txt.5
├── generated.txt.6
├── generated.txt.7
├── generated.txt.8
└── words.pl

0 directories, 10 files
</pre>
<p>If you look at <em>generated.txt.7</em>, you will probably see something similar to:</p>
<pre class="brush: plain; title: ; notranslate">
Hollis
Osgood
glossy
goodly
idylls
igloos
solids
</pre>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=762&amp;md5=004f7808b9b18c95cc015966463f0ca1" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/KYW48ksJf4YepGYssR5qKtRVv7I/0/da"><img src="http://feedads.g.doubleclick.net/~a/KYW48ksJf4YepGYssR5qKtRVv7I/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/KYW48ksJf4YepGYssR5qKtRVv7I/1/da"><img src="http://feedads.g.doubleclick.net/~a/KYW48ksJf4YepGYssR5qKtRVv7I/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/zQ0CWLeoz4s" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/02/words-pl-slogan-word-generator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F02%2Fwords-pl-slogan-word-generator%2F&amp;hidden=1&amp;language=en_GB&amp;category=text&amp;title=words.pl%3A+slogan+word+generator&amp;description=About+a+year+ago%2C+I+was+really+into+playing+this+game+online+where+you+were+given+a+single+sentence+and+you+had+to+use+the+letters+in+that+sentence+to...&amp;tags=github%2Cperl%2Cblog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/02/words-pl-slogan-word-generator/</feedburner:origLink></item>
		<item>
		<title>My Review of Android Open Conference 2011: Complete Video Compilation</title>
		<link>http://feedproxy.google.com/~r/ipreferjim/~3/sZwZYxVM1v0/</link>
		<comments>http://www.ipreferjim.com/2012/01/my-review-of-android-open-conference-2011-complete-video-compilation/#comments</comments>
		<pubDate>Wed, 01 Feb 2012 03:20:20 +0000</pubDate>
		<dc:creator>jimschubert</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.ipreferjim.com/?p=760</guid>
		<description><![CDATA[Originally submitted at O'Reilly Android Open Conference 2011: Complete Video Compilation Android Open Conference 2011: Complete Video Compilation Hours of Android enjoyment By Jim Schubert from Richmond, VA on 1/31/2012 &#160; 5out of 5 Pros: Helpful examples, Easy to understand, Accurate, Concise Best Uses: Intermediate, Student, Expert Describe Yourself: Developer There are a lot of [...]]]></description>
			<content:encoded><![CDATA[<div class="hreview">
<div class="item">
<p><a href="http://oreilly.com/product/0636920023838.do">Originally submitted at O'Reilly</a></p>
<div><img src="http://images.powerreviews.com/images_products/01/18/14846224_100.jpg" class="photo" align="left" style="margin: 0 0.5em 0 0">
<p style="margin-top:0">Android Open Conference 2011: Complete Video Compilation</p>
</div>
<p><a href="http://shop.oreilly.com/product/0636920023838.do" style="display: none;" class="url fn"><span class="fn">Android Open Conference 2011: Complete Video Compilation</span></a></div>
<p><br clear="left">
<p><strong class="summary">Hours of Android enjoyment</strong></p>
<div>By <strong>Jim Schubert</strong> from <strong>Richmond, VA</strong> on <strong><abbr title="2012131T1200-0800" class="dtreviewed" style="border: none; text-decoration: none;">1/31/2012</abbr></strong></div>
<p>
<div style="margin: 0.5em 0; height: 15px; width: 83px; background-image: url(http://images.powerreviews.com/images/stars_small.gif); background-position: 0px -180px;" class="prStars prStarsSmall">&nbsp;</div>
</p>
<div style="display: none"><span class="rating">5</span>out of 5</div>
<p><strong>Pros: </strong>Helpful examples, Easy to understand, Accurate, Concise</p>
<p><strong>Best Uses: </strong>Intermediate, Student, Expert</p>
<p><strong>Describe Yourself: </strong>Developer</p>
<p style="margin-top:1em" class="description">There are a lot of videos here. If you're only planning to write apps for the market, you'll most likely not be interested in the Embedded Android talk or Scala as a Java replacement.  If you don't work on iOS and never plan to, you can probably scan through Nick Farina's talk (sorry, Nick). I found many of the videos worthwhile, whether they related to actual app development or the business of apps.<br xmlns:pr="xalan://com.pufferfish.core.beans.xmlbuilders.xsl.Functions"><br />I also really enjoyed the keynotes.  Tim O'Reilly's talk is probably my favorite because I've been saying the same things about many of Tim's comparisons since I bought my first DROID a couple of years ago.</p>
<p>Even if you're familiar with Android development, you should definitely watch the videos by Ken Jones.  He shows the start of a Twitter client.  Although he didn't get very far in the actual coding, he will point you to the finished code. One aspect I loved about his talks is that he discusses a lot of best practices.  Many tutorials you find online either don't discuss best practices or don't incorporate them.</p>
<p>Be sure to watch the Arduino videos.  I hadn't heard about Arduino before this video and I was very impressed. In fact, I watched the keynote video twice.</p>
<p>Honestly, there are some videos here that I'm not that interested in. That doesn't detract from the overall usefulness of this video collection.  If you're 25% of the way through a video and it hasn't hooked you yet, move onto the next because there is a plethora of information.</p>
<p style="margin-top:0.5em">(<a href="http://www.powerreviews.com/legal/terms_of_use.html" rel="license">legalese</a>)</p>
</div>
 <p><a href="http://www.ipreferjim.com/site/?flattrss_redirect&amp;id=760&amp;md5=f4192296cb7b06949583a98c9fedb8cd" title="Flattr" target="_blank"><img src="http://www.ipreferjim.com/site/wp-content/plugins/flattr/img/flattr-badge-large.png?9d7bd4" alt="flattr this!"/></a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/oN5wKTln_Rk1rbwBabguG2KOShk/0/da"><img src="http://feedads.g.doubleclick.net/~a/oN5wKTln_Rk1rbwBabguG2KOShk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/oN5wKTln_Rk1rbwBabguG2KOShk/1/da"><img src="http://feedads.g.doubleclick.net/~a/oN5wKTln_Rk1rbwBabguG2KOShk/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/ipreferjim/~4/sZwZYxVM1v0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ipreferjim.com/2012/01/my-review-of-android-open-conference-2011-complete-video-compilation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=jimschubert&amp;popout=1&amp;url=http%3A%2F%2Fwww.ipreferjim.com%2F2012%2F01%2Fmy-review-of-android-open-conference-2011-complete-video-compilation%2F&amp;hidden=true&amp;language=en_GB&amp;category=text&amp;title=My+Review+of+Android+Open+Conference+2011%3A+Complete+Video+Compilation&amp;description=Originally+submitted+at+O%27Reilly+Android+Open+Conference+2011%3A+Complete+Video+Compilation+Android+Open+Conference+2011%3A+Complete+Video+Compilation+Hours+of+Android+enjoyment+By+Jim+Schubert+from+Richmond%2C+VA+on+1%2F31%2F2012...&amp;tags=blog" type="text/html" />
	<feedburner:origLink>http://www.ipreferjim.com/2012/01/my-review-of-android-open-conference-2011-complete-video-compilation/</feedburner:origLink></item>
	</channel>
</rss><!-- Served from: www.ipreferjim.com @ 2012-05-18 00:17:44 by W3 Total Cache -->

