<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
>
    <channel>
        <title>John Kary</title>
        <atom:link href="http://johnkary.net/rss.xml" rel="self" type="application/rss+xml" />
        <link>http://johnkary.net</link>
        <description>Official website of John Kary: remote-working software developer and development team consultant based in Lawrence, KS using PHP, Symfony and JavaScript</description>
        <lastBuildDate>Thu, 21 Dec 2017 22:10:34 -0600</lastBuildDate>
        <language>en</language>
        <sy:updatePeriod>hourly</sy:updatePeriod>
        <sy:updateFrequency>1</sy:updateFrequency>
        <generator>https://github.com/mojombo/jekyll</generator>


        <item>
            <title><![CDATA[Who is to blame when the magic runs out?]]></title>
            <link>http://johnkary.net/blog/who-is-to-blame-when-the-magic-runs-out/</link>
            <comments>http://johnkary.net/blog/who-is-to-blame-when-the-magic-runs-out/#disqus_thread</comments>
            <pubDate>Wed, 01 Mar 2017 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[software]]></category>
            <guid>http://johnkary.net/blog/who-is-to-blame-when-the-magic-runs-out</guid>
            <description><![CDATA[Amazon S3 experienced an outage yesterday, making some SaaS products appear broken while others downright unusable.<br><br>When they breakdown, the technologies that empowered us so effortlessly now limit us. We become demoted from value-add to net negative. And it’s all beyond our control because we don’t understand the magic behind that technology’s curtain. We look to project failure onto someone else–onto the real reason we can’t do more.<br><br>But when it’s broken, who is to blame?]]></description>
            <content:encoded><![CDATA[<div class="image">
     <img src="/images/posts/crash.jpg" width="700" title="Who is to blame when the magic runs out?" alt="A plastic LEGO man in race car driver attire flies through the air over his race car that has lost two wheels." style="max-width:100%;">
     <span class="photo-credit">Photo Credit: <a href="https://www.flickr.com/photos/clement127/12194820693/">clement127</a></span>
</div>




<div class="audio">
    <h2>Prefer audio? I narrated this post.<br>Click play to listen. Like it? Let me know! <a href="https://twitter.com/johnkary">@johnkary</a></h2>
    <audio controls preload="metadata">
      <source src="http://johnkary.net-media.s3.amazonaws.com/audio/who-is-to-blame-when-the-magic-runs-out.mp3" type="audio/mpeg">
    Your browser does not support the audio HTML tag.
    </audio>
</div>


<blockquote><p>Everything is amazing, and nobody's happy. &mdash; Louis CK</p></blockquote>

<p>Amazon S3 experienced an outage yesterday, making some SaaS products appear broken while others downright unusable. This outage took down large parts of the internet. Ouch.</p>

<p>The outage wasn't limited to online. Some Internet of Things gadgets depend on services like <a href="https://ifttt.com/">IFTTT</a> to integrate between the gadget interface in the real world and the Internet-connected world. It feels a little like magic when it works as planned.</p>

<p>But when that magic is broken?</p>

<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Mmm. Can't turn some of my lights on at home cos <a href="https://twitter.com/IFTTT">@IFTTT</a> is down. Welcome to the future!<a href="https://twitter.com/internetofshit">@internetofshit</a> <a href="https://t.co/CPw0rGaKR5">pic.twitter.com/CPw0rGaKR5</a></p>&mdash; Stuart Thomas (@stuartthomas) <a href="https://twitter.com/stuartthomas/status/836640721826365440">February 28, 2017</a></blockquote>




<hr>


<p>Not being able to turn on the lights is one thing. What if an outage becomes a fire hazard?</p>

<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Not to raise alarm here or anything, but I&#39;m unable to turn off my <a href="https://twitter.com/hashtag/IoT?src=hash">#IoT</a> oven ever since <a href="https://twitter.com/hashtag/s3?src=hash">#s3</a> went down...

It&#39;s getting kinda toasty in here</p>&mdash; pronto@ °.• 🕚 (@_pronto_) <a href="https://twitter.com/_pronto_/status/836655399336038401">February 28, 2017</a></blockquote>




<hr>


<p>During the outage the Amazon Web Services status page, which itself reports on service availability, ironically experienced an outage itself, due to its own reliance on S3.</p>

<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">The dashboard not changing color is related to S3 issue.  See the banner at the top of the dashboard for updates.</p>&mdash; Amazon Web Services (@awscloud) <a href="https://twitter.com/awscloud/status/836656664635846656">February 28, 2017</a></blockquote>


<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>


<p>When they breakdown, the technologies that empowered us so effortlessly now limit us. We become demoted from value-add to net negative. And it's all beyond our control because we don't understand the magic behind that technology's curtain. We look to project failure onto <em>someone else</em>--onto the <em>real reason</em> we can't do more.</p>

<p><strong>Who is to blame?</strong></p>

<h2>When the Magic Runs Out</h2>

<p>Grant loves Twitter. It's a quick escape on his 30-minute lunch break that's all too short before he crawls back to his call-center cubicle to proposition another unsuspecting victim.</p>

<p>Finally free from the clutches of his headset, Grant fires up his favorite Twitter app, TweetPad. He just wants a laugh, one laugh, to calm the defeat he feels in his heart from making failed direct sales calls all day. But today the funny images aren't showing up. Tapping those familiar buttons does nothing. Pieces of the interface are missing. TweetPad is <strong>broken.</strong> <a href="https://www.youtube.com/watch?v=q8LaT5Iiwo4">This is bullshit.</a></p>

<p>Grant blasts TweetPad in his next tweet, posted from another Twitter client that doesn't rely on S3. TweetPad loses trust amongst Grant's followers as a reliable service. In turn, attracting less users, resulting in less growth, and less profits.</p>

<p><strong>Who is to blame?</strong> TweetPad engineers, for relying on a single point of failure? Amazon, for not providing a reliable service? An Amazon engineering team, who didn't design a fault-tolerant system?</p>

<h2>The Great Lawrence Internet Outage of January 2017</h2>

<p>Where I live in Lawrence, Kansas, a college town of about 90,000, a single ISP supplies internet to the majority of residential and business customers. One afternoon, the #LFK hashtag was ablaze with reports the internet was down. The ISP, fittingly named "WOW!", (yes, that's actually their name) became a parody of itself.</p>

<p>Some local businesses even tweeted they were unable to accept business because their point-of-sale terminals were unavailable without an internet connection.</p>

<p><strong>Who is to blame?</strong> The business, for not having a backup payment processor? The ISP, for not providing a reliable internet service? The point-of-sale terminal, for designing a service with a single point of failure?</p>

<p>(According to the ISP, a fiber-optic cable was severed due to a car crash near a major junction box. <strong>Who is to blame for that one?</strong>)</p>

<h2>The Chain of Blame</h2>

<p>Where does the chain of blame end when everything we do is dependent on so many lower-level things going <em>just right?</em></p>

<p>Ben and Katie's favorite restaurant is closed because the kitchen is unable to prepare food without electricity. Customers are understandably frustrated, but Ben and Katie feel their anniversary dinner plans are ruined. The businesses lose real profits and the unconscious trust they had in it.</p>

<p><strong>Who is to blame?</strong> The restaurant, for not having a redundant power supply? The electric company, for not providing reliable service? The electrician, who improperly installed the down-converter that blew up causing the outage?</p>

<p>The driver's side tire of a late-model four-door car flies off while zipping down the highway. This freak accident causes a crash, claiming the life of the car's driver. Twenty-eight year old Saura was hurrying back to her laboratory to analyze the latest samples in her groundbreaking biology research. Sadly, the world may never know the outcome.</p>

<p><strong>Who is to blame?</strong> The mechanic, for not properly re-tightening the lug nuts? Saura, for not checking her car was in proper working condition before driving? The car manufacturer for designing a non-standard wheel system that cut costs to meet shareholder demands for profits?</p>

<h2>Software Ownership</h2>

<p>Every technology is powered by a magic that we take for granted. Is there magic in software development?</p>

<p>Developers routinely pull open-source libraries into their projects. If a developer can re-use code someone else has already written, it leaves them to focus on higher-level problems and deliver more value more quickly, yada yada. Congrats, that's why we're all here, to build "technology."</p>

<p>However nearly all developers think nothing of how that code came to be or what quality it bares beyond the magic curtain of its public interface.</p>

<p>After a few weeks, a problem crops up. The developer narrows down the problem to a bug in the open-source library that miscalculates payments. Customers are being charged twice the normal price. Oops.</p>

<p>The negative app store reviews practically write themselves. In the short term, no amount of damage control apologies and free coupons will repair the lost trust between the company and its paying customers.</p>

<p><strong>Who is to blame?</strong> The developer who installed the code, for not reviewing the code themselves? The original developer who wrote the bug in the open-source library? What about the open-source community itself, for not seeing and fixing the bug sooner? (Hint: Almost all open-source libraries contain licenses releasing their authors from liability. Good luck filing a lawsuit.)</p>

<h2>Stop Blame Behind the Magic Curtain</h2>

<p>When a failure occurs within your team or company, you know all the details. It wasn't personally your fault and maybe not even your team's fault.</p>

<p>Searching for blame and fault behind the curtain is toxic. It creates a <a href="https://hbr.org/2010/05/how-to-stop-the-blame-game">Blame Culture</a> that drags down the team's creativity and ability to work together to do amazing work. Even searching for blame erodes trust among the very people who should trust each other the most in your organization.</p>

<p>Instead, when something goes wrong, collectively accept the blame. "Yep. It was ME. It was US. We did it. And we're gonna to fix it."</p>

<p>When bugs reach customers it's not likely because the author was incompetent. Instead maybe the team's code review practice was just not good enough. Maybe their <a href="http://amzn.to/2lUV7c8">checklists</a> weren't followed or simply didn't exist.</p>

<p>Throw a party! A weakness has been discovered! This otherwise bad situation becomes an opportunity to improve.</p>

<p>Task those who could be blamed with contributing to a plan that keeps it from happening again.</p>

<h2>Stop Blame Outside the Magic Curtain</h2>

<p>We as makers especially fall victim to blaming technology and its makers when their magic runs out. Certainly <em>we</em> would have never made such a stupid mistake. I mean, how can you screw up Copy &amp; Paste?!</p>

<p>Have compassion. Cultivate empathy. Everyone else is working just as hard to make great things and empower you and everyone else to build even bigger things.</p>

<p>This goes for everything we use in life. The person, people and team who made that tool are probably working their hardest to make the best thing they can given their constraints on time, talent and budget.</p>

<p>Stop for a moment and forgive their oversight. Think of the power you gain from when their tool works correctly. It's much, much more than the small crash or deficiency you just found.</p>

<p>If you can help, submit a bug ticket. Or even submit that diagnostic report after the app launches again. And don't include some smart ass insult.</p>

<p>Stop perpetuate blame culture on both sides of the curtain.</p>

<p>That includes not trashing Amazon for the S3 outage yesterday, and all the products relying on AWS to build great things.</p>

<p>I mean, give it a second. <em>It's going to space!</em></p>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/q8LaT5Iiwo4" frameborder="0" allowfullscreen></iframe></div>

]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[How I almost died in Costa Rica]]></title>
            <link>http://johnkary.net/blog/how-i-almost-died-in-costa-rica/</link>
            <comments>http://johnkary.net/blog/how-i-almost-died-in-costa-rica/#disqus_thread</comments>
            <pubDate>Mon, 06 Feb 2017 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[travel]]></category>
            <guid>http://johnkary.net/blog/how-i-almost-died-in-costa-rica</guid>
            <description><![CDATA[The sun is plunging into the ocean. This might be the most beautiful sunset I’ve ever seen. Because an hour ago that was me, awash in the ocean, in danger of going under.<br><br>I almost died today.<br><br>I’m fortunate to tell this story instead of being its subject. What happened?]]></description>
            <content:encoded><![CDATA[<div class="image">
     <img src="/images/posts/playa-bejuco-costa-rica-sunset.jpg" width="700" title="Sunset in Playa Bejuco, Costa Rica" alt="A golden sunset barely visible over a tree-line as the sun plunges into the ocean. January 26, 2017 in Playa Bejuco, Costa Rica." style="max-width:100%;">
</div>


<p><em>I took this photo from a rooftop terrace where I digested what happened just an hour after the event.</em></p>

<h2>January 26, 2017 &ndash; Playa Bejuco, Costa Rica</h2>

<p>The sun is plunging into the ocean. This might be the most beautiful sunset I've ever seen. Because an hour ago that was me, awash in the ocean, in danger of going under.</p>

<p>I almost died today.</p>

<p>I'm fortunate to tell this story instead of being its subject. What happened?</p>

<p>I wrap work for the day at 3pm, still high on shipping a new software feature for my work project. How do I spend the last 3 hours of sunlight while staying 250 meters from the beach?</p>

<p>Mike is deep in work but I can't contain my excitement. "Yo&hellip; wanna go surfing?"</p>

<p>He hasn't surfed before but after our group's successful surf lessons a few days ago I'm practically a master, right?</p>

<p>Inspecting the two new communal surfboards at our condo, one of the leashes has snapped. That's cool, we can share.</p>

<p>We hit the beach and I do my best Argentinian surf teacher impression, recounting the basics she taught the group: center line, standing up, and holding a martial arts stance for balance. Simple.</p>

<p>The high crashing waves in the distance only add to my excitement. I tighten the velcro-strap surfboard leash to my right ankle and lead us high stepping into the water.</p>

<p>The low tide creates a strong pull that almost sweeps us off our feet. I remain focused on reciting to Mike the tips our instructor gave us.</p>

<p>In position face-down on the surfboard looking over my shoulder, I try timing a few waves. The slick board is difficult to stand up on. Maybe we didn't put enough wax on it? No worries, I'm just warming up.</p>

<p>Meanwhile, Mike idly steadies himself against the unrelenting waves, observing and taking mental notes. He jumps, bobbing up and down to keep his head above each rolling wave before landing again in water cresting at his chest.</p>

<p>Glaring at the shoreline I realize the sun loungers look more like colorful gummy bears than people. We're pretty far out, huh? How did we get here?</p>

<p>The strong undercurrent has dragged us out a meter or two with each wave. And Mike hasn't even had a chance yet. OK, let's get back to shallow water so he can give it a try.</p>

<p>Swimming towards the shore for several minutes the gummy bears continue shrinking. Is this the twilight zone? "This isn't fair," I think to myself. It's not supposed to work like this. I'm a strong swimmer and can't make headway.  Mike trails behind.</p>

<p>I have a bright idea: let's both hop on the board and kick our feet to shore. The next wave comes quickly and the board jets out of control towards shore but without us on it. The rubber tubing of the leash tugs tightly at my ankle.</p>

<p>Mike pogo-sticks on one foot, his mouth slipping below the previously chest-high water. Yo, we're way deep, let's get a move on!</p>

<p>The leash ties itself into tangles as we both try jumping on again. Of course, the leash! I rip off the velcro strap thinking the board will be easier to maneuver.</p>

<p>The next killer wave rips the board toward the shore, forcing me under as it crashes, plunging the board into the white crest of the waves.</p>

<p>I exhale loudly as my head resurfaces looking towards the shore for Mike and the board. I feel naked without the leash tugging at my ankle. Surely Mike is still holding on&hellip;</p>

<p>Mike is a meter in front of me. "Where's the board?!" I exclaim. "It's gone&hellip;"</p>

<p>Early stages of panic start to set in except there is no music like in the movies. This is real life. This is real and this is really happening. We have to get back to shore.</p>

<p>The harder we paddle the harder the waves hit.</p>

<p>Within a few minutes Mike starts losing composure. Lagging behind me he is tiring quickly. His face familiar, like every scary movie where a character is sucked into the jaws of a snarling blue monster.</p>

<p>I give up the ground I have gained to grab his hand. I got us into this mess and I'm going to get us out.</p>

<p>Suddenly I'm responsible for two lives. Trying to swim sideways pulling for both of us I too start to fatigue. The sand gushes up between our toes as each wave reclaims any progress our arms make between waves.</p>

<p>I quickly realize we aren't going to make it back by ourselves. I start hollering for help. Mike echoes me.</p>

<p>A body boarder 100 meters away makes eye contact with us, and seeing how far out we are, waves his arm signaling us to move back to shore. But with the board gone we have nothing to keep us afloat.</p>

<p>Ghastly scenarios begin running through my mind. Not life flashing before my eyes, but the impending worst case scenario. My hometown news recounting my death between Donald Trump outrage and a weekend snow forecast.</p>

<p>I envision my family, coworkers, the woman I'm dating, friends, fellow travelers, all trying to piece together our last whereabouts. The few people that know we went surfing recounting the time they last saw us. Their descriptions of how excitedly we bounded to the beach. Maybe they would even remember us fondly&hellip;</p>

<p>I snap out of it. Back to Mike. He's 30 seconds from full on panic, his eyes darting everywhere looking for certainty. Another worst case scenario appears: Mike dipping below the surface and not coming back up. Could I swim after him and save us both?</p>

<p>"Amigo! Amigo! Amigo!" we holler to the body boarder. It's no use. Our voices are swallowed by the same roaring waves chomping at our heels.</p>

<p>Our hands remain clasped. Their tight grip says, "Stay with me," and "I'm not leaving you." We're each left with one hand switching between treading water and waving for help, as if we're not sure which one is more likely to save us.</p>

<p>I'm going to die out here.</p>

<p>What feels like a hundred waves later, two men appear wading towards us. An older man has our surfboard that must have washed ashore. He is flanked by a shirt-less bronzed man, his long sun-bleached gray hair and thick dad-like handlebar mustache somehow signal he is calm and collected in this otherwise emergency situation.</p>

<p><strong>"What the fuck are you guys doin'?!?!"</strong> His English is impeccable.</p>

<p>"We're fuckin' amateurs&hellip;!" I exclaim. He barks at us to grab onto the board and ride a wave back in. It sounds so simple, now.</p>

<p>The same waves punishing us a moment earlier are now our golden parachute to safety. We thrust toward shore on a wave that rolls all the way into shallow water. The surf angels that lifted our travel-mates into standing position during surfing lessons earlier this week are working overtime.</p>

<p>The sand becomes more sure-footed with each step. The waves less strong. Baby waves splash our ankles.</p>

<p>We share a glance. The silence between us says more than words could.</p>

<p>"I'm really sorry, Mike," I say breaking the sound barrier.</p>

<p>"It's all good, dude&hellip;" he says, way less casually than such words normally warrant.</p>

<p>Walking back to shore our tails remain firmly tucked between our legs. Judgment quickly follows us from behind.</p>

<p>"You guys are lucky&hellip;" The bronzed man's words trail off over a cliff. "We pull a lot of dead bodies out of here." Our eyes lower.</p>

<p>"Thank you&hellip;" He's heard my sheepish appreciation many times before today.</p>

<p>"How much longer you guys down here? We teach rip tide courses." He gestures toward a lookout tower up the coast. "It's how the volunteer life guards make their money." Somehow the $40 fee pales compared to saving our lives.</p>

<p>The setting sun shines brightly behind him, outlining his towering stance in a golden halo as we sink against the driftwood log peering up at him.</p>

<p>"My name's Bob." Is there a Saint Bob? There is now.</p>

<p>Bob leaves and certifies our reckless optimism. Mike and I hold silent a few more minutes to catch our breath. I apologize several more times.</p>

<p>"Welp&hellip; this will make a great story at <em>Shot, Show and Tell</em> later tonight&hellip;"</p>

<h2>Lessons Learned</h2>

<ul>
<li><a href="http://www.ripcurrents.noaa.gov/">Learn to identify rip currents and undercurrents</a> before going to the beach. Ask the locals when you arrive.</li>
<li>Every surfer should have their own board.</li>
<li><strong>Never</strong> unhooked the leash from your leg.</li>
<li>If caught in a rip current or strong undercurrent, <strong>do not</strong> swim directly back to shore. Swim sideways, parallel to shore, then once you no longer feel the strong pull, swim diagonally back to shore.</li>
<li>If you are inexperienced, admit it to yourself, and do not put another person's life at risk based on your overconfidence.</li>
</ul>

]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[My favorite albums of 2016]]></title>
            <link>http://johnkary.net/blog/my-favorite-albums-of-2016/</link>
            <comments>http://johnkary.net/blog/my-favorite-albums-of-2016/#disqus_thread</comments>
            <pubDate>Sat, 31 Dec 2016 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[music]]></category><category><![CDATA[reviews]]></category>
            <guid>http://johnkary.net/blog/my-favorite-albums-of-2016</guid>
            <description><![CDATA[I’m a little old school. In an age of purchasing tracks I still prefer listening to albums start to finish. Appreciating how tracks are arranged one after another and how they transition from one to the next is very important.<br><br>Music and coffee are my lifeblood. Coffee is difficult to share, so please accept my favorite albums released in 2016, including statistics on all music fed into my ears.]]></description>
            <content:encoded><![CDATA[<div class="image">
     <img src="/images/posts/2016-albums-collage.jpg" width="700" title="Collage of album artwork featured later in this article" alt="Album artwork collage" style="max-width:100%;">
</div>


<p>I'm a little old school. In an age of purchasing tracks I still prefer listening to albums start to finish. Appreciating how tracks are arranged one after another and how they transition from one to the next is very important.</p>

<p>Music and coffee are my lifeblood. Coffee is difficult to share, so please accept my favorite albums released in 2016, including statistics on all music fed into my ears.</p>

<p>The below list is unranked and in alphabetical order.</p>

<hr>


<h2>The Black Queen - Fever Daydream</h2>

<p>If <strong>Trent Reznor</strong> never made music again (he snuck in a <a href="spotify:album:2fThnKRzs6iudIAzHP9VOa">new Nine Inch Nails EP</a> in 2016), <strong>The Black Queen</strong> could pick up the industrial electronic torch from where <strong>Nine Inch Nails</strong> leaves off.</p>

<p>While not directly affiliation with Reznor, The Black Queen features two former NIN alumni who can't hide their successful past by grinding out some of the best industrial-rock music programming since <strong>The Fragile</strong>. Frontman and vocalist Greg Puciato (<strong>The Dillinger Escape Plan</strong>) presents his softer side with subdued effect-laden vocals on top of careening 1980's synth-pop reincarnate.</p>

<p>Wait, what year is it?!</p>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/kj9-QKZVW54" frameborder="0" allowfullscreen></iframe></div>




<hr>


<h2>Cubicolor - Brainsugar</h2>

<p>The cooing vocals of Peter Kriek on the <strong>Cubicolor</strong> debut album <strong>Brainsugar</strong> echo those of <strong>Thom York</strong> (<strong>Radiohead</strong>), while its entrancing lo-fi beats spin a subzero cocoon as if <strong>Boards of Canada</strong> were remixed by a deep house DJ in a cold Montreal basement.</p>

<p>Signed to label Anjunadeep created by electronic masterminds <strong>Above &amp; Beyond</strong>, Brainsugar resonates wet atmospheric synths under minimalistic guitar and optimistic electronic beats.</p>

<p>Die hard Radiohead fans will scoff Brainsugar a poor man's interlude, wondering no-man's land somewhere between <strong>Kid A</strong> and <strong>Amnesiac</strong>. Met with an open mind Cubicolor carve their own niche into a crowd of bedroom-borne imitators.</p>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/hyp8CK04E0g" frameborder="0" allowfullscreen></iframe></div>




<hr>


<h2>The Dillinger Escape Plan - Dissociation</h2>

<p><strong>The Dillinger Escape Plan</strong> are an acquired taste. As in, they might last 5 seconds in Dad's stereo before being flung out the window leaving you both grounded and without a Dillinger album.</p>

<p>The band's final studio album <strong>Dissociation</strong> pushes all of their genre-bending extremes to their conclusion. Playing to their strengths, the band waver between unchecked hostility and dizzying shoe gaze, quite often within the same song. Haunts of <strong>Aphex Twin</strong> are scattered across several tracks (the song <strong>Fugue</strong> sounding directly lifted from <strong>Drukqs</strong>) as if we accidentally entered shuffle mode.</p>

<p>Car crash anthems like the track <strong>Honeysuckle</strong> dip in and out of jazz-inspired lulls, early <strong>Norma Jean</strong>-esque <a href="https://www.youtube.com/watch?v=iESjmZBuS8w">guitar-screeching interludes</a>, crushing blast beats and quite literally <strong>some of the most brutal metal breakdowns ever recorded.</strong></p>

<p>The line between incoherent rambling and genius is thin. Dissociation firmly lands in the latter camp and serves a fitting curtain call for a genre-defining band.</p>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/-9RHqEgVGK4" frameborder="0" allowfullscreen></iframe></div>




<hr>


<h2>Every Time I Die - Low Teens</h2>

<p>Seven albums deep <strong>Every Time I Die</strong> continue bravely bending the hardcore metal genre into places others can't touch. <strong>Keith Buckley's</strong> vivid lyrics and scathing analogies breath fire in as many words.</p>

<p>Nostalgic nods hearken to their hardcore-punk influence, complete with fist-pumping chant-alongs littered among crunching southern rock riffs. Each track bravely rolls the dice between genre, speed and tone. While not always successful the band will never fall victim to being labeled stale.</p>

<p>The secret to ETID's continually evolving sound might be regularly employing new drummers. <strong>Low Teens</strong> is the first offering featuring the band's third drummer, Daniel Davison (<strong>Underoath</strong>, <strong>Norma Jean</strong>), whose technical fills, off-time yet in-time hits and punk vibe play perfect compliments to the band's dueling guitars.</p>

<p>Low Teens is a batch of fresh jams that won't win any new fans but will infect their faithful with lyrical ear worms such as (Stare at the sun / Stare directly at the sun) and (I timely ripped into this world / I was born again as a girl) and the boastful lines (I'm joining a cult / joining a cult / joining a cult).</p>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/kqQo2RQMWEM" frameborder="0" allowfullscreen></iframe></div>




<hr>


<h2>Metallica - Hardwired&hellip; To Self-Destruct</h2>

<p><strong>Metallica</strong> have settled their debts and risen from the ashes of <strong>St. Anger's</strong> <a href="https://www.youtube.com/watch?v=Sq3eLdixvCc">snare drum</a> to release the year's biggest surprise: a far from terrible Metallica album. In fact, this is Metallica at their best in 20 years.</p>

<p><a href="/blog/metallica-hardwired-to-self-destruct-album-review/">Read my full review of Hardwired&hellip; To Self-Destruct.</a></p>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/4tdKl-gTpZg" frameborder="0" allowfullscreen></iframe></div>




<hr>


<h2>Moon Tooth - Chromaparagon</h2>

<p>The debut album from <strong>Moon Tooth</strong> forays into the crowded progressive metal genre and emerges with an original sound despite blending styles of their predecessors.</p>

<p>Heavy influence from early nu-metal titans <strong>System of a Down</strong> and oft-forgotten <strong>The Apex Theory</strong> are plentiful throughout the album. Intricate finger-style guitar work plays perfectly against progressive fill-oriented drums (think a less-technical <strong>Between The Buried and Me</strong>) while bass lines wonder their own path up and down the scale behind a wide-range of vocal ranges and styles.</p>

<p>The band are <a href="https://youtu.be/tAeMunz7uwc?t=2041">incredibly talented musicians</a> and take turns showcasing their prowess. With so much musicality packed into each track no two listens yield the same listen. Repeat listens are rewarded with the satisfaction of having memorized many of the intricate musical parts, clearing way to discover nuance that was overshadowed on prior listens.</p>

<p>Don't be surprised to see these guys opening for the genre's more seasoned acts in 2017 as they make a well-deserved name for themselves.</p>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/L_xn0q3NtZw" frameborder="0" allowfullscreen></iframe></div>




<hr>


<h2>2016 Music By The Numbers</h2>

<p>Thanks to <a href="http://last.fm">Last.fm</a> for tracking my every listen since June 2005.</p>

<p><strong>Total Tracks:</strong> 4,487 different tracks<br>
<strong>Total Albums:</strong> 1,385 different albums<br>
<strong>Total Artists:</strong> 777 different artists<br></p>

<p><strong>Top Track:</strong> The Black Queen - Ice to Never (61 listens)<br>
<strong>Top Album:</strong> Every Time I Die - Low Teens (527 listens)<br>
<strong>Top Artist:</strong> Metallica (897 listens)<br></p>

<h2>Top Listens by Album</h2>

<div class="image">
     <img src="/images/posts/2016-top-albums.png" width="622" title="Graph of most-listened to albums in 2016" alt="Graph of most-listened to albums in 2016" style="max-width:100%;border:0;">
</div>


<h2>Top Listens by Artist</h2>

<div class="image">
     <img src="/images/posts/2016-top-artists.png" width="624" title="Graph of most-listened to artists in 2016" alt="Graph of most-listened to artists in 2016" style="max-width:100%;border:0;">
</div>

]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Metallica, Hardwired… To Self-Destruct - Album Review]]></title>
            <link>http://johnkary.net/blog/metallica-hardwired-to-self-destruct-album-review/</link>
            <comments>http://johnkary.net/blog/metallica-hardwired-to-self-destruct-album-review/#disqus_thread</comments>
            <pubDate>Sun, 25 Dec 2016 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[music]]></category><category><![CDATA[reviews]]></category>
            <guid>http://johnkary.net/blog/metallica-hardwired-to-self-destruct-album-review</guid>
            <description><![CDATA[Look. “Hardwired… To Self-Destruct” is to Metallica as “The Force Awakens” is to Star Wars. “New” can never top “old.” The best “new” can only ever co-exist with the “old” by simply not fucking up its reputation. With me so far?]]></description>
            <content:encoded><![CDATA[<div class="image">
     <img src="/images/posts/hardwired.jpg" width="500" title="Metallica: Hardwired To Self-Destruct album art" alt="Metallica: Hardwired To Self-Destruct album art" style="max-width:100%;border:0;">
</div>


<p><a href="spotify:album:1TKCBDHIWLiqjWTxomqniD">Listen on Spotify while reading.</a></p>

<p>Look. <strong>Hardwired… To Self-Destruct</strong> is to Metallica as <strong>The Force Awakens</strong> is to Star Wars. There is no way the "new" can ever top the "old." The best "new" can only ever co-exist with the "old" by simply not fucking up its reputation. With me so far?</p>

<p>Metallica endured a rough ride releasing <strong>Load</strong> (1996), <strong>Reload</strong> (1997) and <strong>Garage Inc.</strong> (1998) mostly departing from the shredding thrash metal songs that made them kings of the genre in the 80's. Long-time fans took it personal, heralding the band sell-outs.</p>

<p>Not content with a musical fall from grace the band confirmed their critics by suing Napster in 2000, drawing a fireball of criticism from progressive technoliterate music fans, only confirming Metallica as washed up rockers playing right into the greedy, technophobic stereotype.</p>

<p>Then what can only be rationalized as retaliation, the band released <strong>St. Anger</strong> (2003) and <strong>Death Magnetic</strong> (2008), both plagued by poor sound production choices and downright terrible songwriting. Undoubtedly these were two of the worst albums ever released by a legitimate metal band.</p>

<p>Frankly everyone (including me) relished watching the wreckage burn.</p>

<p>But somehow with <strong>Hardwired…</strong> Metallica have agreed to settle debts with their fanbase and risen like a phoenix from the ashes of <a href="https://www.youtube.com/watch?v=Sq3eLdixvCc">St. Anger's snare drum</a>. Forgiving the derpy album artwork, most tracks drip of nostalgic as if reincarnated B-sides haunting the band's golden years.</p>

<p>Opening track <strong>Hardwired</strong> is the shortest on the album at 3:11 but rips straight for the jugular landing more unrelenting jabs and body shots than any song twice its length.</p>

<p>The swelling intro and soaring riffs on <strong>Moth Into Flame</strong> feature the album's catchiest lyrical hooks (Same rise and fall / Who cares at all / Seduced by fame / A moth into the flame) all together masquerading as a really damn good <strong>Seek and Destroy</strong> rip off.</p>

<p>But the album begins coasting downhill. The midpoint feels lonely and rhythmically repetitive by <strong>Halo On Fire</strong>, which rolls into <strong>Confusion</strong>, then saved by some solid southern rock riffs on <strong>ManUNkind</strong>, and back to the lonely road with <strong>Here Comes Revenge</strong>. After numerous listens these tracks fade into the background, only briefly cropping into the conscious with catchy ear worm chorus lyrics.</p>

<p>However the final track <strong>Spit Out The Bone</strong> accelerates out of cruise control with a crisp, almost drum-roll snare drum before an upbeat <em>chugga-chugga-chugga-chugga</em> riff reminds us Metallica have life left in them. Numerous breakdowns, wailing guitar solos and double-bass round off the album in the best way possible: leaving us hungry for another listen. The "Repeat Album" setting feeds that hunger ripping straight back into the opening track <strong>Hardwired</strong>.</p>

<p>The album's Deluxe Edition track <strong>Lords of Summer</strong> says it best: (It's been a long lonely winter / The lords of summer have returned!)</p>

<p>Let's be real: only Metallica could save Metallica. With <strong>Hardwired… To Self-Destruct</strong> the band have redeemed over 20 years of disappointing music. Not with their best album of all time, or even of that 20 year span, but one sure to reclaim displaced fans.</p>

<p>While far from flawless or without fat fit for trimming, <strong>Hardwired…</strong> is a return to greatness by simply not fucking it up.</p>

<h2>Bonus Content</h2>

<p>The band's <a href="https://www.youtube.com/Metallica">YouTube channel</a> is straight killing it releasing new content almost daily. For <strong>Hardwired…</strong> the band shot <a href="https://www.youtube.com/watch?v=uhBHL3v4d3I&amp;index=1&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl">music videos</a> for all thirteen tracks.</p>

<p>Each video is stylistically unique, ranging from fully animated story-arc narratives, to making-of in-the-studio style overlaid with album tracks, to quintessentially playing in a warehouse, to professionally recorded concert performances. Those appreciating the lost art of the music video will find value in watching each one.</p>

<ol>
<li><a href="https://www.youtube.com/watch?v=uhBHL3v4d3I&amp;index=1&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl">Hardwired</a></li>
<li><a href="https://www.youtube.com/watch?v=JFAcOnhcpGA&amp;index=2&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl">Atlas, Rise!</a></li>
<li><a href="https://www.youtube.com/watch?v=QlF4rhAbwyc&amp;index=3&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl">Now That We’re Dead</a></li>
<li><a href="https://www.youtube.com/watch?v=4tdKl-gTpZg&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl&amp;index=4">Moth Into Flame</a> (best song on the album?)</li>
<li><a href="https://www.youtube.com/watch?v=yqIQvE5R1tU&amp;index=5&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl">Dream No More</a></li>
<li><a href="https://www.youtube.com/watch?v=WbxH5S9_A3M&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl&amp;index=6">Halo on Fire</a></li>
<li><a href="https://www.youtube.com/watch?v=ZChXK2rdr9M&amp;index=7&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl">Confusion</a></li>
<li><a href="https://www.youtube.com/watch?v=tUVr2xnGIEo&amp;index=8&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl">ManUNkind</a> (best video?)</li>
<li><a href="https://www.youtube.com/watch?v=FpF8Wa2yQH0&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl&amp;index=9">Here Comes Revenge</a></li>
<li><a href="https://www.youtube.com/watch?v=IkVG-qXRgfo&amp;index=10&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl">Am I Savage?</a></li>
<li><a href="https://www.youtube.com/watch?v=2Mkq6GFLIsk&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl&amp;index=11">Murder One</a></li>
<li><a href="https://www.youtube.com/watch?v=m46Z0-HXySo&amp;index=12&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl">Spit Out the Bone</a></li>
<li><a href="https://www.youtube.com/watch?v=zaZswCtNmEg&amp;list=PLJvQXRgtxlumAHceNRk3cx3P7MZVUCdBl&amp;index=13">Lords of Summer</a></li>
</ol>


<p>Yes, that is Metallica, posting their entire new album on YouTube. For free.</p>

<p>My, my, how times have changed.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Attending and speaking at DrupalCon, May 2016]]></title>
            <link>http://johnkary.net/blog/attending-and-speaking-at-drupalcon-may-2016/</link>
            <comments>http://johnkary.net/blog/attending-and-speaking-at-drupalcon-may-2016/#disqus_thread</comments>
            <pubDate>Mon, 16 May 2016 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[conferences]]></category><category><![CDATA[drupal]]></category>
            <guid>http://johnkary.net/blog/attending-and-speaking-at-drupalcon-may-2016</guid>
            <description><![CDATA[Last week I spoke at DrupalCon 2016 in New Orleans. While I anticipated a fun conference with great talks, I came away more impressed with the Drupal community as a whole. Their tireless effort to include anyone and everyone was refreshing in a way I can only describe as “human.” There’s no question that the future of the Drupal ecosystem is bright, mainly thanks to the amazing people surrounding it.]]></description>
            <content:encoded><![CDATA[<div class="image">
    <a href="https://www.flickr.com/photos/drupalassoc/26985071205/in/dateposted-public/"><img src="/images/posts/drupalcon-2016-attendees.jpg" title="DrupalCon 2016 New Orleans Group Photo" width="100%"></a>
</div>


<p>Last week I delivered a talk <a href="/talks/#rethinking-loops">Rethinking Loops</a> at <a href="https://events.drupal.org/neworleans2016/">DrupalCon 2016</a> in New Orleans. DrupalCon is a HUGE conference, with over 3000+ attendees. Easily the largest conference I have attended, let alone spoken at.</p>

<p>The conference <a href="https://www.youtube.com/watch?v=p2K2JHFMh1o">records all sessions</a> and posts them within hours of the talk. Very impressive turnaround time!</p>

<p>My session is below and slides are available: <a href="http://johnkary.net/slides/loops/drupalcon-2016/">Rethinking Loops slides</a></p>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/p2K2JHFMh1o" frameborder="0" allowfullscreen></iframe></div>


<h2>Rethinking Loops</h2>

<p>Being the last session, on the last day, where attendees also had the option of attending a session by the creator of Drupal, I was a little worried if people would even show up&hellip;</p>

<p>I walked in fifteen minutes early and the room was already 75% full, with more filing in after me. Relief. I've heard other speakers grow more anxious the more people are in the room. Not me. I feed off of it. Especially a small, intimate, packed room.</p>

<p>A packed room instantly validates what I'm speaking about and gives me confidence that what I have to say is important, insightful and valuable&mdash;a feeling I've struggled with most of my life.</p>

<div style="margin-bottom:2.2em">
    <blockquote class="twitter-tweet" data-lang="en" data-tweet-limit="1"><p lang="en" dir="ltr">The room is packed, I love it! Let&#39;s do this last session <a href="https://twitter.com/hashtag/DrupalCon?src=hash">#DrupalCon</a>. Rethinking Loops, 278. <a href="https://t.co/NJAZQT8A1D">pic.twitter.com/NJAZQT8A1D</a></p>&mdash; John Kary (@johnkary) <a href="https://twitter.com/johnkary/status/730838704965570560">May 12, 2016</a></blockquote>
    <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>


<h2>Attendee Feedback</h2>

<p>DrupalCon facilitates speaker feedback thru their website. I always appreciate feedback so I can improve my talk and overall become a better speaker. If you have any feedback after viewing the talk above please <a href="/contact/">ping me</a>.</p>

<p>Attendees who were gracious enough to submit feedback all gave very positive remarks. Some of the highlights:</p>

<blockquote>One of the very best sessions at DrupalCon this year, and one of the best speakers I've heard. I didn't completely agree with the speaker, but I love seeing different ways of thinking.</blockquote>




<blockquote>Overall excellent presentation. Probably the best one I saw (I only missed 3 slots)</blockquote>




<blockquote>One of the most valuable sessions I attended. Can't wait to pass this on to my colleagues at our next code review.</blockquote>




<blockquote>Very smooth presentation. Even at 2pm on the last day of conf. Had me wide awake and interested. I wish more sessions were like this.</blockquote>


<p>Attendees and other speakers have specifically raved about how my talk uses pre-recorded video to demonstrate refactoring code in one segment. It's actually ten separate videos across ten separate slides, but with a few slideshow and production tricks it appears seamless when talking over it. Here's the <a href="https://youtu.be/p2K2JHFMh1o?t=2597">exact point in the recorded session where I show this</a>. Maybe I'll do a future post on how to produce it.</p>

<h2>Social: First-Time Attendee Social</h2>

<p>Because of its scale the conference does well to acclimate first-time attendees with its First-Time Attendee Social the night before the first day of sessions.</p>

<p>We were handed Bingo cards where each cell described a person we needed to meet. Things like "From the East coast" and "Knows what a BOF is" and "Member of the Drupal Association." We were ushered into an intentionally small area, given free beer, water and cookies, and bounced around like pinballs meeting each other and morphing between conversational groups. The format worked well and I talked with several people again throughout the conference.</p>

<p>Coincidentally I met a person who lives in the same city as me (Lawrence, Kansas, population ~90,000) that's involved with publishing <a href="https://drupalwatchdog.com/">Drupal Watchdog</a>, a magazine with articles interesting to Drupal users and developers. Funny we had to travel all the way to New Orleans to meet each other.</p>

<h2>Social: Pub Crawl</h2>

<p>One of the attendees took it upon himself to loosely organize a pub crawl after the First-Time Attendee Social. I like beer, and meeting other developers over beer, so I knew before the event I'd be going.</p>

<p>Three of us met in the lobby to walk to the first stop, The Courtyard Brewery, about a half mile away. We arrived and quickly saw groups of other conference attendees scattered about. Many attendees I talked with worked in higher education, mostly state universities, while others worked for agencies with quick turn around times. The groups intermingled for an hour before heading to the second bar, The Avenue.</p>

<p>The group eventually ended up out back on the patio, and after meeting a few other people that work with remote development teams overseas I had to call it a night about 10:00pm. I still had my backpack/laptop with me and I didn't want it to get too late, knowing I had a half-mile walk between my cable car stop and where I was staying. Walking by myself I simply didn't want to be a target for theft. I hoped the cable car right outside the bar on St. Charles street and made it home without incident.</p>

<h2>Event: Pre-Note</h2>

<p>Tuesday, the first day of conference sessions, began with what can best be described as musical theater. The "pre-note" was endlessly hyped at the opening ceremony and first-time attendee social, so I was curious to see what it was all about. At 8:00am I felt I sacrificed a little sleep to get there to see it and wanted it to be worth my time.</p>

<p>My skepticism peaked as the event began with some awkward crowd-rousing "I can't hear you! Are you excited?!" type banter from the first people on stage. But by the end I realized it was absolutely like NOTHING I had ever seen at a development conference and that many other tech communities could learn a lot from this community.</p>

<p>Several prominent contributors to the Drupal community sporting intricate headdresses and shiny skin-tight full-body leotards took the stage, their costumes leaving nothing to the imagination. The actors' lines and musical performances were delivered with as much gracefulness as a high school drama, while their individual singing voices were surprisingly good&mdash;an obvious reason they were selected to lead the performance.</p>

<p>As the performance wore on and the other casts of characters were introduced and performed their dance and musical numbers, all with equally cheesy lyrics and all spoofing classic pop culture songs, I realized something&hellip;</p>

<p>This performance wasn't trying to <em>be</em> anything. Instead it was the coming together of the community's most prominent figureheads and splaying themselves in a highly vulnerable and slightly embarrassing light. All for the sake of making us smile, laugh, and root for them. It reinforced how everyone attending, whether speaker, volunteer, core committer, or simple attendee, were all simply people. A reminder that those people are not their titles within the community, nor their contributions to the ecosystem. They are people just like you and me.</p>

<p>The pre-note was a microcosm of the Drupal community: people from widely varying backgrounds willing to accept and embrace anyone wishing to take part. And most importantly a community that doesn't take themselves too seriously. It's truly rare to see all of these characteristics within one community set within an industry conspiring in favor of stereotypical ultra-serious, ultra-assertive, yet often ultra-shy geeks.</p>

<p>I must give special mention to Larry Garfield's solo dancing and singing number. I've met and talked with Larry several times at previous conferences, and before the pre-note I would've described him as a vocal but reserved person. Maybe he's a lot like you. But after seeing him get up on stage wearing only pants, his signature black vest yet no blue undershirt, then singing and dancing all over the stage to the tune of "I'm Too Sexy," I have an even higher esteemed respect for everything Larry does for the wider PHP and Drupal communities. There's simply nothing he can't and won't do.</p>

<p><a href="https://youtu.be/u6VoeELTfvM?t=984">Here's the video stream</a> beginning at Larry's performance. He's absolutely a much better singer and dancer than me. Thank you for everything you do, Larry.</p>

<h2>Sessions</h2>

<p>With three days packed full of sessions it was sometimes hard to decide which talks to attend. Two sessions I attended stood out in their relevancy to modern web application development:</p>

<h3><a href="https://events.drupal.org/neworleans2016/sessions/graphql-meets-drupal">GraphQL Meets Drupal</a></h3>

<p><a href="https://facebook.github.io/react/blog/2015/05/01/graphql-introduction.html">GraphQL</a> is a game-changer in querying for data. This isn't the first time I'd seen GraphQL, but it was the first time I'd seen <a href="https://github.com/graphql/graphiql">GraphiQL</a>, an in-browser tool for building and executing GraphQL queries. Basically it introspects the GraphQL schema from a server and provides auto-complete to build a query, then you can execute the query and see the results instantly.</p>

<p>The speaker also tailored how he continues to work on a Drupal module to expose Drupal data via GraphQL. It sounds like the project is at a minimum viable state and has room for more contributors.</p>

<p>I love the idea of GraphQL and believe it can supplant REST as the best way to expose data, at least for web applications:</p>

<ul>
<li>The shape of the response matches the shape of the query, making it more predictable to parse</li>
<li>It's backed by a spec protocol, meaning any software stack can expose its data as long as it fits the schema format, and any client stack that speaks HTTP can send GraphQL queries</li>
</ul>


<h3><a href="https://events.drupal.org/neworleans2016/sessions/elm-frontend-guarantees">Elm - Frontend with Guarantees</a></h3>

<p><a href="http://www.elm-lang.org/">Elm</a> is a functional language for rendering browser-based user interfaces. I have been hearing about it in bits and pieces over the last year and I continue to be enticed by it.</p>

<p>Code speaks louder than any description at this point, so check out this <a href="http://guide.elm-lang.org/index.html">basic counter built with Elm</a>.</p>

<p>Elm is statically-typed and compiles to JavaScript. That might sound terrible, and it probably is. But what's awesome about it is that data only flows one way within an Elm program: from its source of truth (model) downward into the components whose rendering depends on it (view). If data changes the component is re-rendered again. No need to inspect the current state of the UI component and decide how to change it. The data simply flows thru the render pipeline again to get the new result. If this idea sounds just like those in <a href="https://facebook.github.io/react/">React</a> that's because it is.</p>

<p>One-way data flow and re-rendering components will be core features of the future of building user interface applications on the web. Distributed state is tough and we're only now seeing quality languages and tools for managing it. Elm is a language tailored to that paradigm.</p>

<h2>Event: Drupal Trivia</h2>

<p>On the last night of the conference, after the closing keynote, and after the event mourning the death of Drupal 6, there was a trivia night held at the World War II Museum in New Orleans. What a fantastic venue! Several planes from the World War II era hung ominously suspended above 100 small round tables.</p>

<div class="image">
    <img src="/images/posts/ww2-planes.jpg" title="Planes flown in World War II" width="100%">
</div>


<p>Each table composed of 5 people made up a team. The trivia panel entertained us with five rounds of trivia questions, ranging from very Drupal specific ("Name the date when Drupal 8.0.0 was released. NO, you do NOT get extra points for giving the exact UTC timestamp or its git SHA1, you nerds!") all the way to nuanced browser questions ("What is the maximum number of stylesheets Internet Explorer 10 allows? Is it A, 1023; B, 4095; C, 8190.") or needing to identify a sponsor company's name by only its logo.</p>

<p>Trivia was a very fun and lively atmosphere, and reminded me of <a href="https://twitter.com/jmikola">Jeremy Mikola's</a> PHP Jeopardy events at other PHP conferences. More conferences should do this because we're all geeks&mdash;we love sharing the small tidbits we pick up about our favorite languages, frameworks and technology. Trivia night gives us a chance to be rewarded for this useless knowledge all while growing our camaraderie of dissenters.</p>

<h2>Conclusion</h2>

<p>Most conferences I've attended put most of their emphasis on the talks. What's different about DrupalCon is their focus on community and events. Yes the talks are good, but it's all the supplemental activities packed into the schedule that opened my eyes to what's possible during a conference:</p>

<ul>
<li>A full day of trainings and summits before the main conference begins</li>
<li>A well-produced theatrical music production with elaborate costumes and lines and musical numbers and dances</li>
<li>Three solid keynotes: one technical, one inter-personal/social, and one personal wellbeing.</li>
<li>Three days and eight tracks (!) of unconference meetings. People can share a similar interest and informally get together to talk and discuss. DrupalCon calls these "Birds of a Feather," or BOF for short.</li>
<li>Three days talks with the ability to choose between eleven different talks per slot</li>
<li>Lively after-parties after each day of the conference filled with music and dancing</li>
<li>One day of "Sprints" where attendees contribute back to the Drupal ecosystem for both technical and non-technical people.</li>
</ul>


<p>The Drupal community has blown me away. I'm astounded at their inclusiveness and openness across personalities and technical abilities. It's no wonder this conference and its community are one of the most diverse tech communities still going strong.</p>

<p>I've long felt Drupal 8 could take the Drupal ecosystem to the next level. The momentum of the Drupal ecosystem over the years has now met with more widely adopted technical practices of the greater software community. It has matured into a rich platform ready to move into the enterprise professional development market. After this conference all of those feelings were confirmed.</p>

<p>Professionally I'm in a fantastic spot to benefit from developing on top of Drupal 8. I've been using the Symfony components that power Drupal since their inception 5 years ago, and since then have been building web applications using all the principles and tools Drupal has only recently adopted. There is tremendous immediate opportunity in the Drupal ecosystem for experienced PHP developers to find high-demand, well-paid work. It's in my best professional interest to learn more about exactly how people are using Drupal today, and begin consulting with teams wanting to adopt Drupal 8.</p>

<p>Attending and speaking at this DrupalCon solidified for me that the Drupal ecosystem is one of PHP's biggest assets and the Drupal platform is a very viable solution for certain types of software.</p>

<p>It's not only the technology that will continue to keep Drupal relevant for the coming years but its tirelessly passionate community of diverse technical talent. Having embraced a more modern and technically sound infrastructure in the last few years Drupal is now at the perfect cross-section of technical potential and bolstering community to foster huge growth opportunities in the coming years.</p>

<p>Thank you DrupalCon organizers, volunteers, speakers, sponsors and attendees for making my first DrupalCon truly memorable. I look forward to seeing you again soon!</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[The Cosmos series reinvented, Cosmos: A Spacetime Odyssey]]></title>
            <link>http://johnkary.net/blog/the-cosmos-series-reinvented-cosmos-a-spacetime-odyssey/</link>
            <comments>http://johnkary.net/blog/the-cosmos-series-reinvented-cosmos-a-spacetime-odyssey/#disqus_thread</comments>
            <pubDate>Sun, 23 Mar 2014 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[picks]]></category><category><![CDATA[carl-sagan]]></category>
            <guid>http://johnkary.net/blog/the-cosmos-series-reinvented-cosmos-a-spacetime-odyssey</guid>
            <description><![CDATA[Carl Sagan’s original series The Cosmos is inspiring a reinvented series with the same mission: amaze people with the truths of science.]]></description>
            <content:encoded><![CDATA[<div class="embed-container"><iframe title="Cosmos: A Spacetime Odyssey Official Trailer" src="https://www.youtube.com/embed/XFF2ECZ8m1A" frameborder="0" allowfullscreen></iframe></div>


<h2>Cosmos: A Spacetime Odyssey</h2>

<p>Glow-in-the-dark stars dot the dark ceiling above my top bunk bed, my brother sleeping below me. Space has fascinated me since I was a kid. Science was cool, and I learned early in life that the mysterious world around me could be understood through observation and experimentation.</p>

<p>Between late high school and early college I lost touch with science. The immediacy of computers and technology gripped me and I had to understand them deeper. I don't regret those years for they birthed my programming career. It wasn't until after college in my mid-20's, amid much self-reflection and reevaluation, that I space and science found their way back to me.</p>

<div class="image">
    <a href="/images/posts/pale_blue_dot.jpg"><img src="/images/posts/pale_blue_dot.jpg" title="Pale Blue Dot" width="420"></a>
</div>


<p>It was 2009 when I <a href="http://www.youtube.com/watch?v=zSgiXGELjbc&amp;list=PLWS2mFp_C6rPPIPDdjOqPIM3b-yxxcFmu">first discovered</a> Carl Sagan's TV series, <a href="http://en.wikipedia.org/wiki/Cosmos:_A_Personal_Voyage">Cosmos: A Personal Voyage</a> (1980). (The entire series is on YouTub or Hulu. <a href="http://www.youtube.com/watch?v=ClPShKs9Kr0">Start here.</a>) Carl Sagan's way of confidently asserting the seemingly unknowable captivated me. <a href="http://johnkary.net/blog/thoughts-on-carl-sagans-pale-blue-dot/">His poetic words stuck with me</a> long after I first heard them. Repeat viewings have instilled a framework for making sense of myself and my insignificant place in the universe.</p>

<p>When news broke in late 2011 that Cosmos was being reborn with new episodes, I was overwhelmed with excitement. Finally, the ideas that inspired me so deeply might inspire a new generation and update with the latest findings in the 30-some years since the original.</p>

<p><a href="http://en.wikipedia.org/wiki/Cosmos:_A_Spacetime_Odyssey">Cosmos: A Spacetime Odyssey</a> (2014) is hosted and narrated by astrophysicist Neil deGrasse Tyson. Writers for the original Cosmos, Ann Druyan and Steven Stower, are writing the new series. Music by Alan Silvestri, who scored the movie <a href="http://www.imdb.com/title/tt0118884/">Contact</a> based on Sagan's novel of the same name, is on board to score the series.</p>

<p>The show and its writing pay tribute to the original by sprinkling oft-quoted clips of Sagan, and reuse metaphors such as <a href="http://www.youtube.com/watch?v=uWmbZ1K6ID0">The Spaceship of the Imagination</a>, <a href="http://www.youtube.com/watch?v=Ln8UwPd1z20">The Cosmic Calendar</a> and the <a href="http://www.youtube.com/watch?v=gZpsVSVRsZk#t=355">Evolution in 40 Seconds</a> animation. The visuals effects rival that of modern blockbuster films. Animation segments exploring historic scientific figures are stylish yet original and take what could be yet another boring historical vantage point and make it very engaging.</p>

<p>Realizing the Cosmos's ultimate goal would mean viewers rethinking what they believe to be true about who they are, where they come from and where they're going.</p>

<div class="image">
    <a href="/images/posts/cosmos_animation.jpg"><img src="/images/posts/cosmos_animation.jpg" title="Animation still from Cosmos: A Spacetime Odyssey" width="614"></a>
</div>


<p>Cosmos currently premieres new episodes on Sundays at 9:00pm Eastern on Fox. Previous episodes can be viewed online at <a href="http://www.cosmosontv.com/cosmosontv/full-episodes">CosmosOnTV.com</a> and on Netflix.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Introducing SpeedTrap: Finding slow tests in your PHPUnit test suite]]></title>
            <link>http://johnkary.net/blog/introducing-speedtrap-finding-slow-tests-in-your-phpunit-test-suite/</link>
            <comments>http://johnkary.net/blog/introducing-speedtrap-finding-slow-tests-in-your-phpunit-test-suite/#disqus_thread</comments>
            <pubDate>Mon, 10 Feb 2014 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[php]]></category><category><![CDATA[phpunit]]></category><category><![CDATA[testing]]></category>
            <guid>http://johnkary.net/blog/introducing-speedtrap-finding-slow-tests-in-your-phpunit-test-suite</guid>
            <description><![CDATA[As your test suite grows, you can expect it to run longer. But if you’re not careful, some slower tests can creep in and disproportionately increase your suite’s total execution time.<br><br>Introducing SpeedTrap: a lightweight PHPUnit listener that reports on slow-running tests right in your console.]]></description>
            <content:encoded><![CDATA[<blockquote><p>This post may now be outdated. See the <a href="https://github.com/johnkary/phpunit-speedtrap">johnkary/phpunit-speedtrap</a> project on GitHub for the most recent instructions.</p></blockquote>

<p>All developers should strive to write "fast tests," and "fast" will be different for each developer, language and software stack. Traditionally, unit tests should be very fast, a few milliseconds or faster, while functional tests and end-to-end tests will run a bit longer, maybe a few seconds.</p>

<p>As your test suite grows, you can expect it to run longer. But if you're not careful, some slower tests can creep in and disproportionately increase your suite's total execution time.</p>

<h2>SpeedTrap</h2>

<p><a href="https://github.com/johnkary/phpunit-speedtrap">SpeedTrap</a> is a PHPUnit Listener that reports on slow-running tests in your PHPUnit test suite console output.</p>

<div class="image" style="margin-bottom:1.2em">
    <a href="http://i.imgur.com/Zr34giR.png"><img src="http://i.imgur.com/Zr34giR.png" width="100%" alt="Screenshot of terminal output of SpeedTrap"></a>
</div>


<p>Many factors affect test execution time. A test not properly isolated from variable latency (database, network, etc.) and even basic load on your test machine will cause test times to fluctuate.</p>

<p>SpeedTrap helps you <strong>identify slow tests</strong> but cannot tell you <strong>why</strong> those tests are slow. For that you should check out something like <a href="https://github.com/sebastianbergmann/phpunit-testlistener-xhprof">PHPUnit_Listener_XHProf</a> to help identify specifically which methods in your call stack are slow.</p>

<h2>Installation</h2>

<p>SpeedTrap is installable via <a href="http://getcomposer.org">Composer</a> and should be added as a dev dependency:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">composer require --dev johnkary/phpunit-speedtrap</span></code></pre></figure></p>

<h2>Usage</h2>

<p>Enabled it with default configuration by adding the following to your test suite's <code>phpunit.xml</code> file:</p>

<p><figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span></span><span class="nt">&lt;phpunit</span> <span class="na">bootstrap=</span><span class="s">&quot;vendor/autoload.php&quot;</span><span class="nt">&gt;</span>
...
    <span class="nt">&lt;listeners&gt;</span>
        <span class="nt">&lt;listener</span> <span class="na">class=</span><span class="s">&quot;JohnKary\PHPUnit\Listener\SpeedTrapListener&quot;</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/listeners&gt;</span>
<span class="nt">&lt;/phpunit&gt;</span></code></pre></figure></p>

<p>Now run your test suite as normal. If tests run that exceed the slowness threshold (500ms by default), SpeedTrap will report on them in the console after the suite completes.</p>

<h2>Configuration</h2>

<p>SpeedTrap has two configurable parameters:</p>

<ul>
<li><strong>slowThreshold</strong> - Number of milliseconds a test takes to execute before being considered "slow" (Default: 500ms)</li>
<li><strong>reportLength</strong> - Number of slow tests included in the report (Default: 10 tests)</li>
</ul>


<p>These configuration parameters are set in <code>phpunit.xml</code> when adding the listener:</p>

<p><figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span></span><span class="nt">&lt;phpunit</span> <span class="na">bootstrap=</span><span class="s">&quot;vendor/autoload.php&quot;</span><span class="nt">&gt;</span>
    <span class="c">&lt;!-- ... other suite configuration here ... --&gt;</span><span class="nt">&lt;/p&gt;</span>

<span class="nt">&lt;pre&gt;&lt;code&gt;</span><span class="ni">&amp;lt;</span>listeners<span class="ni">&amp;gt;</span>
    <span class="ni">&amp;lt;</span>listener class=&quot;JohnKary\PHPUnit\Listener\SpeedTrapListener&quot;<span class="ni">&amp;gt;</span>
        <span class="ni">&amp;lt;</span>arguments<span class="ni">&amp;gt;</span>
            <span class="ni">&amp;lt;</span>array<span class="ni">&amp;gt;</span>
                <span class="ni">&amp;lt;</span>element key=&quot;slowThreshold&quot;<span class="ni">&amp;gt;</span>
                    <span class="ni">&amp;lt;</span>integer<span class="ni">&amp;gt;</span>500<span class="ni">&amp;lt;</span>/integer<span class="ni">&amp;gt;</span>
                <span class="ni">&amp;lt;</span>/element<span class="ni">&amp;gt;</span>
                <span class="ni">&amp;lt;</span>element key=&quot;reportLength&quot;<span class="ni">&amp;gt;</span>
                    <span class="ni">&amp;lt;</span>integer<span class="ni">&amp;gt;</span>10<span class="ni">&amp;lt;</span>/integer<span class="ni">&amp;gt;</span>
                <span class="ni">&amp;lt;</span>/element<span class="ni">&amp;gt;</span>
            <span class="ni">&amp;lt;</span>/array<span class="ni">&amp;gt;</span>
        <span class="ni">&amp;lt;</span>/arguments<span class="ni">&amp;gt;</span>
    <span class="ni">&amp;lt;</span>/listener<span class="ni">&amp;gt;</span>
<span class="ni">&amp;lt;</span>/listeners<span class="ni">&amp;gt;</span>
<span class="nt">&lt;/code&gt;&lt;/pre&gt;</span>

<span class="nt">&lt;p&gt;&lt;/phpunit&gt;</span></code></pre></figure></p>

<p>This allows you to set your own criteria for "slow" tests, and how many you care to know about.</p>

<h2>Inspiration</h2>

<p>SpeedTest was inspired by Rspec's <code>-p</code> option that displays feedback about slow tests.</p>

<h2>License</h2>

<p>phpunit-speedtrap is available under the MIT License.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Stop building broken password inputs (and how to work around the offenders)]]></title>
            <link>http://johnkary.net/blog/stop-building-broken-password-inputs/</link>
            <comments>http://johnkary.net/blog/stop-building-broken-password-inputs/#disqus_thread</comments>
            <pubDate>Mon, 13 Jan 2014 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[security]]></category><category><![CDATA[javascript]]></category><category><![CDATA[ux]]></category><category><![CDATA[ui]]></category>
            <guid>http://johnkary.net/blog/stop-building-broken-password-inputs</guid>
            <description><![CDATA[I have run into some sites (usually within a security-focused domain like banking or health care) that use misleading or downright bad security practices during their user registration process. Overall these practices decrease the user experience, and at worst encourage their users to succumb to poor security practices.<br><br>Why might these sites choose to do this? What are the side effects? And how can savvy developers work around them?]]></description>
            <content:encoded><![CDATA[<p>I spent some time recently setting up a new username and password on a site handling some of my finances. This is the type of site that thinks security questions and a "personal image" are a good addition to the security theater they subject their users to when creating an account.</p>

<p>When registering my account on this specific site, I randomly generated a long, complex password and copied it to my clipboard with the intent to paste it into the password and password-confirmation text inputs.</p>

<p>I placed my cursor in the password box and pressed "⌘ + V" to paste my clipboard text into the input. Nothing. Maybe I didn't copy the password correctly. I generated another password and pasted again. Nothing. Ah great, <strong>another site preventing its users from pasting text into text boxes.</strong></p>

<p>I tweeted the following, partly wondering allowed, partly in frustration:</p>

<blockquote class="twitter-tweet" lang="en"><p>Why do some sites disallow pasting from clipboard into text inputs? I really don&#39;t want to type my 32-character randomly generated passwords</p>&mdash; John Kary (@johnkary) <a href="https://twitter.com/johnkary/statuses/419928097551437824">January 5, 2014</a></blockquote>


<p>Site features should be oriented towards business goals, right? So what business goal might a company have with not allowing a user to paste text?</p>

<p>I image the business saying their goal was "to decrease incorrect registration data, resulting in less user frustration and less required user support." Sounds good in theory... Keep users happy when using the site, and keep company expenses down by requiring less staff to support users misusing their software.</p>

<h2>Balancing the sliding scale</h2>

<p>Implementing information security is a trade-off between convenience and security of data. This almost always functions as a sliding scale: practices that are easier to use are often less secure. But the most secure actions often take much more effort on behalf of the user. Too much inconvenience and the user will forgo implementing security all together.</p>

<p>When I think of "online security" I think of things like encryption, anonymity and privacy. The last piece, "privacy," is usually implemented as segregation of data access, implemented via user account and password.</p>

<p>If an account can only be accessed by one who knows its password, data is reasonably more secure than if it were publicly available. (The inconveniences in using other stronger authentication mechanisms have probably prevented widespread adoption for most consumer-facing applications.) So in order to use online accounts with some added privacy, users tolerate the inconvenience of creating a new user account and password for each site they want to access privately.</p>

<h2>Solving the wrong problem</h2>

<p>Most sites require entering a username and entering the same password twice when creating an account.</p>

<p>The current standard practice to decrease erroneous password entry is requiring the user to enter their password twice: once in two separate text inputs. A password like <code>il0vemydog123!</code> isn't too inconvenient to type two times on a full sized keyboard, and is perhaps mildly inconvenient to type twice on a mobile phone keyboard. The trade-off is the inconvenience of typing a password twice <strong>is less inconvenient</strong> than if the user were to mistype their password once and <strong>become locked out of their account.</strong></p>

<p>Yet I firmly believe <strong>password confirmation boxes are solving the wrong problem.</strong> The only reason a user must type a password twice is to decrease the likelihood they mistyped their intended password one of the two times. Why might they mistype it? <strong>Because the user can't see the result of their typing.</strong></p>

<p>I side with <a href="http://www.lukew.com/about/">Luke Wroblewski</a> on how to solve this issue:</p>

<ol>
<li>Password boxes should offer a "Hide/Show" button adjacent to a single password box that obscures the user's typing by replacing each character with an asterisk.</li>
<li>Using this strategy, <strong>the user's password is typed in plain-text and is visible by default</strong>, leading to visual confirmation that the password was typed correctly the first time.</li>
</ol>


<p>Mobile devices continue to increase in penetration, where typing is much more difficult, so developers should firstly reevaluate this long-held and broken user experience practice of requiring a user to confirm their password using two password boxes.</p>

<p>Luke does a great job illustrating the pros and cons of this approach in his post <a href="http://www.lukew.com/ff/entry.asp?1653=">Mobile Design Details: Hide/Show Passwords</a>.</p>

<h2>Disabling pasting text could decrease password security</h2>

<p>My friend and go-to security expert, Bryan Geraghty, offered this insight in response to my earlier tweet:</p>

<blockquote class="twitter-tweet" data-conversation="none" lang="en"><p><a href="https://twitter.com/johnkary">@johnkary</a> Not allowing users copy and paste passwords means that you are likely an easier brute-force target. We don&#39;t report that ATM.</p>&mdash; Bryan C. Geraghty (@archwisp) <a href="https://twitter.com/archwisp/statuses/419934717392076800">January 5, 2014</a></blockquote>


<p>Why might this be the case?</p>

<p>A long, complex password is inherently difficult to type. If a user must type a complex password twice, there are probably a certain percentage of users that will forgo typing a long password and either use a shorter password or one that requires less key-presses to type.</p>

<p>This is where Bryan's point aligns with the security sliding scale: a user experience that makes it more difficult to use a better security practice will likely lead to a choice that is <strong>easier for the user and less secure for their data.</strong> In this case, a weaker password is easier to guess or extract via a <a href="https://en.wikipedia.org/wiki/Brute-force_attack">brute force attack</a>.</p>

<h2>Working around the inability to paste</h2>

<p>Sites that disable the ability to paste do this with JavaScript, often by listening for the <code>paste</code> browser Event, then preventing the default behavior that would normally take the clipboard text and place it at the cursor location. Less sophisticated preventions might simply intercept a platform-specific key combination.</p>

<p>There are several ways we can work around this restriction by executing our own JavaScript:</p>

<ol>
<li>Use a password vault browser plugin with "auto-fill" capability</li>
<li>The browser's Location bar prefixed with <code>javascript:</code></li>
<li>The browser's Developer Console</li>
<li>A custom bookmarklet</li>
<li>Write a custom browser extension</li>
</ol>


<h2>Password Vault Browser Plugin</h2>

<p>Password vaults like <a href="https://lastpass.com/">LastPass</a> or <a href="https://agilebits.com/onepassword">1Password</a> have browser extensions that will fill in a saved username and password into a site's text inputs for user login. These extensions use JavaScript and a stored input selector associated with a site/URL to target each field that must be filled.</p>

<p>These extensions are your best bet for security by&hellip;</p>

<ol>
<li>Preventing you from ever needing to manually type your password (preventing keylogger interception)</li>
<li>URL/domain matching prevents entering credentials into phishing sites appearing as legitimate sites.</li>
</ol>


<p>If you're not using a password vault yet, I highly encourage you to start today! If you're not yet ready for that commitment, keep reading. We can still circumvent sites preventing you from fully using their registration form.</p>

<h2>Custom JavaScript solutions</h2>

<p>The remaining four solutions require us to execute custom JavaScript we write ourselves. This vanilla JavaScript will force our own text value into a text input.</p>

<p>But first you need to find a way for JavaScript to select the target text input. There are several ways to select the element (id, class, name), but the easiest is by its HTML "id" attribute via <code>getElementById()</code>. If your site requires a different solution, I will leave that to you to investigate.</p>

<p><figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span></span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;password&#39;</span><span class="p">).</span><span class="nx">value</span> <span class="o">=</span> <span class="s1">&#39;mypassword&#39;</span><span class="p">;</span></code></pre></figure></p>

<p>We can execute this code on the page in a few ways.</p>

<h2>Location Bar</h2>

<p>The Location bar can execute JavaScript when code is prefixed with <code>javascript:</code>:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">javascript:function fillpw()%7Bdocument.getElementById(&#39;password&#39;).value=&#39;mypassword&#39;;%</span>7Dfillpw<span class="o">()</span><span class="p">;</span></code></pre></figure></p>

<p>The downsides of this approach are that this text could be sent to the browser vendor (via auto-complete engine or other statistics-gathering techniques), submitted to the browser's default search engine if mistyped, or persisted in the Location bar's plain-text history.</p>

<p>At the risk of exposing your password in persisted plain-text, there are better solutions.</p>

<h2>Developer Console</h2>

<p>If you only need to override the ability to paste just one time, the following technique is probably your next best option after the password vault technique above.</p>

<p>Open the developer console using its keyboard shortcut (<a href="https://developers.google.com/chrome-developer-tools/docs/shortcuts#opening-devtools">Chrome</a>, <a href="https://support.mozilla.org/en-US/kb/keyboard-shortcuts-perform-firefox-tasks-quickly#w_tools">Firefox</a>) or menu selection, and enter the following JavaScript:</p>

<p><figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span></span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;password&#39;</span><span class="p">).</span><span class="nx">value</span> <span class="o">=</span> <span class="s1">&#39;mypassword&#39;</span><span class="p">;</span></code></pre></figure></p>

<h2>Custom Bookmarklet</h2>

<p>If you have one offending site that you repeatedly visit, you'll want a more dynamic solution. A bookmarklet stored in your browser's Bookmarks Bar can execute JavaScript, just like the "Location Bar" suggestion above.</p>

<p>The rough steps go something like so:</p>

<ol>
<li>Create a bookmark by dragging a link to your browser's Bookmarks Bar.</li>
<li>Edit the bookmark you just created and enter the following JavaScript, replacing the element's id with your offending site's input id:</li>
</ol>


<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">javascript:function fillpw()%</span>7Bdocument.getElementById<span class="o">(</span>prompt<span class="o">(</span><span class="s1">&#39;Password element id:&#39;</span><span class="o">))</span>.value<span class="o">=</span>prompt<span class="o">(</span><span class="s1">&#39;Password:&#39;</span><span class="o">)</span><span class="p">;</span>%7Dfillpw<span class="o">()</span><span class="p">;</span></code></pre></figure></p>

<p>Using this solution, you can click the bookmarklet and be prompted for the HTML id of the text input you would like to modify its value, then prompted for the text you would like to enter. Entering via a JavaScript prompt prevents your password from being stored in plain-text at any point in the process.</p>

<p>You can now navigate to the offending site, click the bookmarklet in your bookmark bar and enter in your credentials.</p>

<h2>Custom Browser Extension</h2>

<p>If there are many offending sites you must visit, you could expand the "Custom Bookmarklet" solution with more code that switches on the current <code>document.location.host</code> or <code>document.location.href</code> to target the correct username and password widgets for a given URL.</p>

<p>If you're considering this solution, you're probably much better off by adopting a password vault that already has this functionality built-in. That is unless you really want to learn how to build a browser extension.</p>

<p>Each browser has its own conventions for writing extensions or add-ons, and exactly how to do that will be outside the scope of this post, but check the following resources:</p>

<ul>
<li><a href="http://developer.chrome.com/extensions/getstarted.html">Getting Started Building Chrome Extensions</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Building_an_Extension">Building a Firefox extension</a></li>
</ul>


<h2>Wrap up</h2>

<p>It should be your responsibility as an informed developer that the next time you're tasked with creating a registration or login form, to instead opt for a single, visible-password entry widget that offers a corresponding button to obscure the user's typing.</p>

<p>When creating your next registration form I suggest following the implementation details in Luke Wroblewski's post: <a href="http://www.lukew.com/ff/entry.asp?1653=">Mobile Design Details: Hide/Show Password</a>.</p>

<p>Let's continue making the web more friendly and easier to use, and lead our users to embrace better security practices.</p>

<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Review: Tom Bihn - Buzz Sling Bag]]></title>
            <link>http://johnkary.net/blog/review-tom-bihn-buzz-sling-bag/</link>
            <comments>http://johnkary.net/blog/review-tom-bihn-buzz-sling-bag/#disqus_thread</comments>
            <pubDate>Sun, 05 Jan 2014 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[hardware]]></category>
            <guid>http://johnkary.net/blog/review-tom-bihn-buzz-sling-bag</guid>
            <description><![CDATA[I am fairly picky when it comes to bags. As one piece of equipment I use daily, it must feel like an extension of myself. I won’t put up with a sub-par bag with lots of bulk and extra features I won’t use.<br><br>When I first heard about the Buzz bag by Tom Bihn it sounded great, even if it cost more than any bad I had ever owned, so I ordered it. After a solid 18 months of use I can detail the great, good and my wish list for its next version.]]></description>
            <content:encoded><![CDATA[<blockquote><p>This post is in no way endorsed or sponsored by the companies whose products are mentioned. These are my own uninfluenced thoughts.</p></blockquote>

<div class="image">
    <img src="/images/posts/buzz-bag.jpg" title="Tom Bihn Buzz Sling Bag">
</div>


<p>I discovered <a href="http://www.tombihn.com/">Tom Bihn bags</a> from a <a href="http://randsinrepose.com/archives/a-bag-of-holding/">post</a> on the <a href="http://randsinrepose.com/">Rands in Repose</a> blog. A lot like me, its author is a bag geek. I devoured all the different scenarios and reasons he is picky in selecting a bag. I nodded my head at all of his points, and by the end was picking apart my existing backpack and immediately had a bad case of bag envy. I was sold on the thought of a new bag, and behold, his post linked off to a few possibilities.</p>

<p>Before picking up the Tom Bihn <a href="http://www.tombihn.com/PROD/TB0152.html">Buzz Sling Bag</a>, I must admit I was guilty of carrying a bulky backpack. I didn't have much of a choice when my previous laptop was a behemoth 17" MacBook Pro, but when I downsized to a 13" MacBook Air in Summer 2012 I wanted a bag that also matched the streamlined nature of the Air.</p>

<h2>Bag Requirements</h2>

<p>My (new) criteria for a daily computer bag includes the following:</p>

<ul>
<li>Low profile</li>
<li>Streamlined look</li>
<li>Big enough to store a MacBook Air and charger with some room to spare</li>
<li>Easy on-off</li>
<li>No useless straps</li>
<li>Sturdy, can take some punishment</li>
<li>Not scream NERDY BACKPACK</li>
</ul>


<p>The Tom Bihn site has a limited selection of bags, making it easy to pick one simply based on core bag size. Choosing the Buzz bag over the others was an easy choice.</p>

<h2>Impressions</h2>

<p>I could weave these thoughts into prose but they are fairly easy to skim:</p>

<ul>
<li><p><strong>Shoulder Strap</strong> - well formed and fit for the bag. It's wide and sturdy enough, but relatively thin in its thickness, so it doesn't add much bulk when slung over the shoulder and chest.</p></li>
<li><p><strong>Shoulder Strap</strong> - a little uncomfortable at first and stiff out of the box. I was hoping for thicker padding on the side against the body. When fully loaded (laptop + charger + a thick book + all random cables and gadgets) it weighs unevenly on my shoulder and causes some discomfort.</p></li>
<li><p><strong>Shoulder Strap Buckle</strong> - a heavy duty plastic buckle fastens the upper strap to the lower strap near the base of where the strap affixes to the bottom of the bag. The buckle is solidly built and makes a satisfying click sound when fastening. The buckle makes it extremely easy to slip out of the bag without lifting it over your head.</p></li>
<li><p><strong>Shoulder Strap Thumb Loop</strong> - There's a sturdy loop near the phone/wallet pocket on the shoulder strap to insert your thumb and support the weight of the bag after unlatching the buckle. The placement and size of the loop feels very natural when using it. It is easy to then sling the bag somewhere or hold it up to reattach the plastic buckle.</p></li>
<li><p><strong>Shoulder Strap Contour</strong> - At first the bag didn't feel secured to my body no matter what length I extended or retracted the shoulder strap. After a few months of repeated daily use the strap gave a little and felt more contoured.</p></li>
<li><p><strong>Shoulder Strap Pocket</strong> - Perfectly cradles my iPhone 4S (with thin case) or my <a href="http://www.koyono.com/Slimmy-Wallet-Alternative-p/m17546.htm">Slimmy wallet</a>. It has enough padding to where I wouldn't be afraid putting it in there and flinging my bag around under normal circumstances. But I find it's my permanent home for my wallet when on the go with my bag.</p></li>
<li><p><strong>Shoulder Strap Pocket</strong> - Pocket flip-cover is just the right size to still allow a set of normal earbuds to plug into the top of an iPhone 4S or 5 while secured in the pocket.</p></li>
<li><p><strong>Side Pocket</strong> - A tight fit to accommodate my admittedly large 750mL Nalgene water bottle. The pocket looks like it's more made for a thin aluminum water bottle or small travel umbrella.</p></li>
<li><p><strong>Zippers</strong> - Two words: HEAVY DUTY. They almost seem to be more heavy duty than a low-profile bag should be. They are perhaps the most durable piece of the bag and I could see them continuing to zip perfectly even after years of use. Not to mention they have a waterproof lining over them. If I were caught in a moderate rain shower I wouldn't be fearful of water seeping in.</p></li>
<li><p><strong>Zippers</strong> - Both outside pockets offer dual-zippers that zip both ways.</p></li>
<li><p><strong>Waist Strap</strong> - Would be useful if I planned on using the bag during a more active activity like hiking. The straps hang too low off the back when not in use to tolerate it being attached at all times. Not to mention it looks sloppy hanging off the bag, and goes against my "no useless straps" requirement. My primary use case is transporting my laptop between home and destination so I removed it. It unbuckles after some moderate pressure on each of the metal-hinge plastic connections to the bag.</p></li>
<li><p><strong>Large Pocket</strong> - Has a great padded separator between the laptop compartment and the main bag compartment. My 13" MacBook Air with Encase padded sleeve comfortably fits in the bag. It could easily accommodate a 15" MacBook Pro, too. The other side of the padded separator is a great place to stash larger cables, a tablet, a medium sized book (400 pages, hardback) or even a second laptop. Even with those compartments full, the bag does not appear bulky.</p></li>
<li><p><strong>Small Pocket</strong> - Well-angled slots to add pens. They slip in almost sideways and fit like a glove with two normal-sized pens in each slot. There is a bigger pouch for other things, but it feels awkwardly sized. Perhaps it's meant to fit a normal-sized wallet, but I find it's not well secured. I can place a pack of gum or chap stick in there but might find them removed from where I packed them when I arrive. There is also a 6-inch strap with clips on both ends: one to affix it to the bag, one to easily clip your keyring so it doesn't get lost in the clutter.</p></li>
<li><p><strong>Flying</strong> - When flying with the bag it works perfect as a "personal item" by fitting up under the seat with plenty of room to relax your feet on the bag.</p></li>
</ul>


<h2>What would I change?</h2>

<p>I wish the very front of the bag had a stash pouch for small items such headphones, pack of gum, chap stick, nail clippers, etc. Instead I keep several Ziplock bags, one with cables and connectors, another with over the counter medications and similar. I can open the full front zipper pocket and dig deep into the bag without things tumbling out, but wish it was easier to store things more quickly.</p>

<h2>Final Verdict</h2>

<p>Overall I'm still very happy with this bag. Its streamlined look and low profile make it great for a daily carrier from point A to B or even when flying. It doesn't offer the quick-access pouch I came to rely on with previous bags, but this bag is a keeper and will be my primary bag for years to come.</p>

<blockquote><p>Sadly this bag design has been "retired" and is no longer available for purchase from the vendor. But if this bag is any indication of the quality of their other bags, I wouldn't hesitate to buy another model.</p></blockquote>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Useful Commands For Efficient Symfony2 Development]]></title>
            <link>http://johnkary.net/blog/useful-commands-for-efficient-symfony2-development/</link>
            <comments>http://johnkary.net/blog/useful-commands-for-efficient-symfony2-development/#disqus_thread</comments>
            <pubDate>Mon, 02 Dec 2013 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[symfony]]></category>
            <guid>http://johnkary.net/blog/useful-commands-for-efficient-symfony2-development</guid>
            <description><![CDATA[These commands allow me, and hopefully you, to work faster and more efficiently with the Symfony2 framework.]]></description>
            <content:encoded><![CDATA[<blockquote><p>This post was published when <strong>Symfony Standard Edition 2.3</strong> was the latest stable release, and may be outdated for later Symfony versions.</p></blockquote>

<p>Have you explored all of the Console commands that ship with the Symfony Standard Edition? The long list of tasks after entering the <code>php app/console</code> command might feel a bit overwhelming at first, but the more you use Symfony, the more comfortable you'll feel and the more likely you will have memorized a few common commands.</p>

<p>But there are a few commands that you don't hear much about that are very useful during every day development, but only garnish a quick blurb in the <a href="http://symfony.com/doc/current/index.html">official documentation</a>.</p>

<p>I spend most of my working day developing web applications where the frontend JavaScript application is fed data by an API built on the Symfony2 framework. What follows are some of the protips I've devised to help me work more efficiently and some of the non-obvious Symfony commands I use on a daily basis. I hope they help you develop faster and more efficiently!</p>

<ol>
<li><a href="#alias">Alias your most common Symfony commands</a>

<ol type="a">
<li><a href="#alias-sf">Alias the Symfony Console itself</a></li>
<li><a href="#alias-sfcc">Alias the cache:clear command</a></li>
<li><a href="#alias-sft">Alias the command to run your test suite</a></li>
<li><a href="#alias-history">Find other common commands you can alias</a></li>
</ol>
</li>
<li><a href="#container-service">Finding a specific service id or a service's class</a></li>
<li><a href="#container-parameter">Finding a specific container parameter</a></li>
<li><a href="#router-debug">Finding a specific route name or URI</a></li>
<li><a href="#router-name">Show all info about a specific route by its name</a></li>
<li><a href="#router-match">Find which route matches a given URI</a></li>
<li><a href="#database">Query your database from the CLI</a>

<ol type="a">
<li><a href="#database-dql">DQL queries</a></li>
<li><a href="#database-sql">SQL queries</a></li>
</ol>
</li>
</ol>


<hr />

<h2><a name="alias"></a> 1. Alias your most common Symfony commands</h2>

<p>There are 3 commands I use so often I have short bash aliases setup for each:</p>

<h3><a name="alias-sf"></a> Alias the Symfony Console itself</h3>

<p>Developing with Symfony2, you will type <code>php app/console</code> many, many times. Having a faster way to type this is an instant productivity boost.</p>

<p>Add the following line to your <code>.bash_profile</code> file in your home directory to take your first step towards Symfony console mastery:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">alias sf=&#39;php app/console&#39;</span></code></pre></figure></p>

<p>Now reload your .bash_profile within you current shell session with the command <code>source ~/.bash_profile</code> and you can now access the Symfony console by typing <code>sf</code> in all places you would type <code>php app/console</code>.</p>

<p>Try using your new powers and ensure they're working properly:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf
<span class="go">Symfony version 2.3.7 - app/dev/debug&lt;/p&gt;</span>

<span class="go">&lt;p&gt;Usage:</span>
<span class="go">  [options] command [arguments]&lt;/p&gt;</span>

<span class="go">&lt;p&gt;Options:</span>
<span class="go">  --help           -h Display this help message.</span>
<span class="go">  --quiet          -q Do not output any message.</span>
<span class="go">...</span></code></pre></figure></p>

<h3><a name="alias-sfcc"></a> Alias the cache:clear command</h3>

<p>You will clear the Symfony cache relatively often, so it deserves its own shell alias. As many will tell you, step 1 of troubleshooting Symfony issues is first clearing your cache!</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">alias sfcc=&quot;php app/console cache:clear&quot;</span></code></pre></figure></p>

<p>The command <code>sfcc</code> will now clear your <a href="http://symfony.com/doc/current/cookbook/configuration/environments.html">"dev" environment</a> cache. The <code>--env=dev</code> option is implied for all Symfony commands unless otherwise specified, but you can easily specify any other environment too:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sfcc --env<span class="o">=</span><span class="nb">test</span></code></pre></figure></p>

<h3><a name="alias-sft"></a> Alias the command to run your test suite</h3>

<p>You should be running your test suite often during development. The full command to run the Symfony test suite using PHPUnit is a bit long:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> bin/phpunit -c app</code></pre></figure></p>

<p>Not too bad, but again, given how often you will be running this command, it deserves its own alias. (If you don't use PHPUnit, modify the alias to use whatever your test runner requires):</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">alias sft=&#39;bin/phpunit -c app&#39;</span></code></pre></figure></p>

<p>Quickly reload your .bash_profile again via <code>source ~/.bash_profile</code> and you can now execute your test suite by typing <code>sft</code>:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sft
<span class="go">PHPUnit 3.7.28 by Sebastian Bergmann.&lt;/p&gt;</span>

<span class="go">&lt;p&gt;Configuration read from /path/to/your/project/app/phpunit.xml.dist&lt;/p&gt;</span>

<span class="go">&lt;p&gt;...............................................................  63 / 120 ( 52%)</span>
<span class="go">.........................................................&lt;/p&gt;</span>

<span class="go">&lt;p&gt;Time: 312 ms, Memory: 5.75Mb&lt;/p&gt;</span>

<span class="go">&lt;p&gt;OK (120 tests, 236 assertions)</span></code></pre></figure></p>

<p>With your new-found powers you can now quickly do things like only run tests within a specific directory:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sft src/Acme/DemoBundle/</code></pre></figure></p>

<p>Or run a specific test by its name:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sft --filter<span class="o">=</span>testUserStartsAsActive</code></pre></figure></p>

<p>Or quickly generate code coverage:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sft --coverage-html<span class="o">=</span>coverage</code></pre></figure></p>

<p>Of course you could always run these exact commands without the alias, but the key is allocating less mental energy to mundane things like typing long commands for commonly used commands.</p>

<h3><a name="alias-history"></a> Find other common commands you can alias</h3>

<p>You could try noticing your habits and alias other common commands, but why not let your console history just tell you?</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> <span class="nb">history</span> <span class="p">|</span> grep <span class="s1">&#39;php app/console&#39;</span>
<span class="go">[... your most recent history containing &#39;php app/console&#39; will appear here ...]</span></code></pre></figure></p>

<h2><a name="container-service"></a> 2. Finding a specific service id or a service's class</h2>

<p>Often you will need to see if your newly defined <a href="http://symfony.com/doc/current/book/service_container.html#what-is-a-service">service</a> is wired up how you intend it to be. The following command will display all defined services in the Symfony2 <a href="http://symfony.com/doc/current/book/service_container.html">service container</a>:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf container:debug</code></pre></figure></p>

<p>If you have an idea of what you're looking for, pipe this command's output to <code>grep &lt;you search string here&gt;</code>. For example, let's list all the services containing the word "doctrine":</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf container:debug <span class="p">|</span> grep doctrine
<span class="go">database_connection                                    n/a       alias for doctrine.dbal.default_connection</span>
<span class="go">doctrine                                               container Doctrine\Bundle\DoctrineBundle\Registry</span>
<span class="go">doctrine.dbal.connection_factory                       container Doctrine\Bundle\DoctrineBundle\ConnectionFactory</span>
<span class="go">doctrine.dbal.default_connection                       container stdClass</span>
<span class="go">doctrine.orm.default_entity_manager                    container EntityManager5292d7ee8f526_546a8d27f194334ee012bfe64f629947b07e4919__CG__\Doctrine\ORM\EntityManager</span>
<span class="go">doctrine.orm.default_manager_configurator              container Doctrine\Bundle\DoctrineBundle\ManagerConfigurator</span>
<span class="go">doctrine.orm.entity_manager                            n/a       alias for doctrine.orm.default_entity_manager</span>
<span class="go">doctrine.orm.validator.unique                          container Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator</span>
<span class="go">doctrine.orm.validator_initializer                     container Symfony\Bridge\Doctrine\Validator\DoctrineInitializer</span>
<span class="go">form.type_guesser.doctrine                             container Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser</span>
<span class="go">monolog.logger.doctrine                                container Symfony\Bridge\Monolog\Logger</span>
<span class="go">sensio_framework_extra.converter.doctrine.orm          container Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\DoctrineParamConverter</span></code></pre></figure></p>

<p>This command also accepts a service id as its first argument and will output even more information about that how it is wired up. Let's look at the service with id "twig.loader":</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf container:debug twig.loader
<span class="go">[container] Information for service twig.loader&lt;/p&gt;</span>

<span class="go">&lt;p&gt;Service Id       twig.loader</span>
<span class="go">Class            Symfony\Bundle\TwigBundle\Loader\FilesystemLoader</span>
<span class="go">Tags</span>
<span class="go">    - twig.loader                    ()</span>
<span class="go">Scope            container</span>
<span class="go">Public           yes</span>
<span class="go">Synthetic        no</span>
<span class="go">Required File    -</span></code></pre></figure></p>

<p>(I wish this output contained things like what other services/parameters are wired into it, what factory methods are run when instantiated, etc. If you know how to find this output from the Console, please comment below.)</p>

<h2><a name="container-parameter"></a> 3. Finding a specific container parameter</h2>

<p>While <code>sf container:debug</code> outputs a list of services, calling this command with the additional option <code>--parameters</code> will dump a list of all <a href="http://symfony.com/doc/current/components/dependency_injection/parameters.html">service container parameters</a> and their values. This is useful to ensure your config or bundle is overriding the intended parameter or just to see what all parameters are available without digging into a Bundle's <a href="http://symfony.com/doc/current/cookbook/bundles/extension.html">Extension</a> or <a href="http://symfony.com/doc/current/cookbook/bundles/extension.html">Configuration</a> files:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf container:debug --parameters</code></pre></figure></p>

<p>Using this command's output with grep, like in the previous example, is also your friend.</p>

<p>You can also use the similar option <code>--parameter="..."</code> (notice no "s" in "parameter") to find the value for a specific parameter. Let's find exactly which class will be used for Doctrine's EntityManager by finding the value for the "doctrine.orm.entity_manager.class" parameter:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf container:debug --parameter<span class="o">=</span><span class="s2">&quot;doctrine.orm.entity_manager.class&quot;</span>
<span class="go">Doctrine\ORM\EntityManager</span></code></pre></figure></p>

<h2><a name="router-debug"></a> 4. Finding a specific route name or URI</h2>

<p>Like finding values in the Service Container, a similar command exists to search Symfony's <a href="http://symfony.com/doc/current/book/routing.html">Router</a> for route names and URI paths:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf router:debug
<span class="go">[router] Current routes</span>
<span class="go">Name                Method Scheme Host Path</span>
<span class="go">index               ANY    ANY    ANY  /</span>
<span class="go">users_list          ANY    ANY    ANY  /users/</span>
<span class="go">users_new           ANY    ANY    ANY  /users/new</span>
<span class="go">users_edit          ANY    ANY    ANY  /users/{id}</span></code></pre></figure></p>

<p>I often use this command as a dummy-check that my Controller <a href="http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/routing.html#usage">@Route annotations</a> are wired properly and that they have the correct <a href="http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/routing.html#route-method">@Method annotation</a> values.</p>

<h2><a name="router-name"></a> 5. Show all info about a specific route by its name</h2>

<p>The first optional argument to <code>router:debug</code> is the route name. This shows all details for the route named "users_list":</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf router:debug users_list
<span class="go">[router] Route &quot;users_list&quot;</span>
<span class="go">Name         users_list</span>
<span class="go">Path         /users/</span>
<span class="go">Host         ANY</span>
<span class="go">Scheme       ANY</span>
<span class="go">Method       ANY</span>
<span class="go">Class        Symfony\Component\Routing\Route</span>
<span class="go">Defaults     _controller: Acme\DemoBundle\Controller\UsersController::indexAction</span>
<span class="go">Requirements NO CUSTOM</span>
<span class="go">Options      compiler_class: Symfony\Component\Routing\RouteCompiler</span>
<span class="go">Path-Regex   #^/users/$#s</span></code></pre></figure></p>

<h2><a name="router-match"></a> 6. Find which route matches a given URI</h2>

<p>You might know the URI path but not the route name. The <code>router:match</code> command works like <code>router:debug</code> but does the reverse operation by accepting a URI argument instead of the route name.</p>

<p>The following example shows which route matches the URI "/users":</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf router:match /users
<span class="go">Route &quot;users_list&quot; matches&lt;/p&gt;</span>

<span class="go">&lt;p&gt;[router] Route &quot;users_list&quot;</span>
<span class="go">Name         users_list</span>
<span class="go">Path         /users/</span>
<span class="go">Host         ANY</span>
<span class="go">Scheme       ANY</span>
<span class="go">Method       ANY</span>
<span class="go">Class        Symfony\Component\Routing\Route</span>
<span class="go">Defaults     _controller: Acme\DemoBundle\Controller\UsersController::indexAction</span>
<span class="go">Requirements NO CUSTOM</span>
<span class="go">Options      compiler_class: Symfony\Component\Routing\RouteCompiler</span>
<span class="go">Path-Regex   #^/users/$#s</span></code></pre></figure></p>

<h2><a name="database"></a> 7. Query your database from the CLI</h2>

<p>It can be a hassle to write up a functional test or other code that executes DQL or SQL you are tweaking for a new query or troubleshooting an existing query. Thankfully Doctrine offers two commands that let you run queries straight from the command-line.</p>

<h3><a name="database-dql"></a> DQL queries</h3>

<p>You can query your database using <a href="http://docs.doctrine-project.org/en/latest/reference/dql-doctrine-query-language.html">raw DQL</a> right from the command-line using the command <code>doctrine:query:dql</code>. Just pass in the full DQL you want to execute:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> sf doctrine:query:dql <span class="s2">&quot;SELECT u.firstName, u.lastName, u.lastLogin FROM AcmeDemoBundle:User u&quot;</span> --hydrate<span class="o">=</span>array&lt;/p&gt;

<span class="go">&lt;p&gt;array (size=1)</span>
<span class="go">  0 =&gt;</span>
<span class="go">    array (size=3)</span>
<span class="go">      &#39;firstName&#39; =&gt; string &#39;John&#39; (length=4)</span>
<span class="go">      &#39;lastName&#39; =&gt; string &#39;Smith&#39; (length=5)</span>
<span class="go">      &#39;lastLogin&#39; =&gt;</span>
<span class="go">        object(stdClass)[325]</span>
<span class="go">          public &#39;&lt;strong&gt;CLASS&lt;/strong&gt;&#39; =&gt; string &#39;DateTime&#39; (length=8)</span>
<span class="go">          public &#39;date&#39; =&gt; string &#39;2013-11-26T00:00:00-06:00&#39; (length=25)</span>
<span class="go">          public &#39;timezone&#39; =&gt; string &#39;America/Chicago&#39; (length=15)</span></code></pre></figure></p>

<p>Appending the option <code>--hydrate=array</code> like in the previous example is also useful if your selected entities have other entity relationships, where the resulting var_dump() of object data creates a lot of additional clutter. Hydrating as an array is a bit cleaner to look at if you're only interested in the data and not the underlying object structure.</p>

<h3><a name="database-sql"></a> SQL queries</h3>

<p>You can also directly query your database using raw SQL without connecting through the <code>mysql</code> binary or a GUI application. Like querying for DQL, the connection data from <code>parameters.yml</code> or <code>config.yml</code> is used, so there's no hassle with passing the right credentials with each query:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="gp">$</span> php app/console doctrine:query:sql <span class="s2">&quot;SELECT * from users&quot;</span>&lt;/p&gt;

<span class="go">&lt;p&gt;array (size=1)</span>
<span class="go">  0 =&gt;</span>
<span class="go">    array (size=5)</span>
<span class="go">      &#39;id&#39; =&gt; string &#39;5&#39; (length=1)</span>
<span class="go">      &#39;firstName&#39; =&gt; string &#39;John&#39; (length=4)</span>
<span class="go">      &#39;lastName&#39; =&gt; string &#39;Smith&#39; (length=5)</span>
<span class="go">      &#39;logins&#39; =&gt; null</span>
<span class="go">      &#39;lastLogin&#39; =&gt; string &#39;2013-11-26&#39; (length=10)</span></code></pre></figure></p>

<h2>Did I miss anything?</h2>

<p>What do you think? Did you learn something that can make you more productive? Are there other productivity wins you wish I had included? I'd love to hear your feedback in the comments section below!</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Deserializing XML with JMSSerializerBundle in Symfony2]]></title>
            <link>http://johnkary.net/blog/deserializing-xml-with-jms-serializer-bundle/</link>
            <comments>http://johnkary.net/blog/deserializing-xml-with-jms-serializer-bundle/#disqus_thread</comments>
            <pubDate>Mon, 22 Jul 2013 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[symfony]]></category>
            <guid>http://johnkary.net/blog/deserializing-xml-with-jms-serializer-bundle</guid>
            <description><![CDATA[Serializing existing objects with the Symfony2 JMS Serializer Bundle is pretty easy, but deserializing a third-party XML response is a bit more work.]]></description>
            <content:encoded><![CDATA[<blockquote><p>Note: This post was published when <strong>Symfony Standard Edition 2.3</strong> and <strong>jms/serializer 0.12.0</strong> were the latest stable releases, and may be outdated with later versions.</p></blockquote>

<p>The <a href="http://jmsyst.com/libs/serializer">JMS Serializer library</a> and its accompanying <a href="http://jmsyst.com/bundles/JMSSerializerBundle">Symfony2 bundle</a> are must-haves if your PHP-based application needs to expose an HTTP API. If you have used it before, you're probably most familiar with its ability to transform an object graph to XML or JSON, and this couldn't be easier in Symfony2:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="s1">&#39;jms.serializer&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">serialize</span><span class="p">(</span><span class="nv">$user</span><span class="p">,</span> <span class="s1">&#39;json&#39;</span><span class="p">);</span></code></pre></figure></p>

<p>The resulting JSON might look something like this:</p>

<p><figure class="highlight"><pre><code class="language-json" data-lang="json"><span></span><span class="p">{</span>
   <span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="s2">&quot;John&quot;</span><span class="p">,</span>
   <span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="s2">&quot;Kary&quot;</span><span class="p">,</span>
   <span class="nt">&quot;logins&quot;</span><span class="p">:</span><span class="mi">5</span><span class="p">,</span>
   <span class="nt">&quot;last_login&quot;</span><span class="p">:</span><span class="s2">&quot;2013-07-21T01:16:22-0500&quot;</span><span class="p">,</span>
   <span class="nt">&quot;address&quot;</span><span class="p">:{</span>
      <span class="nt">&quot;number&quot;</span><span class="p">:</span><span class="s2">&quot;555&quot;</span><span class="p">,</span>
      <span class="nt">&quot;street&quot;</span><span class="p">:</span><span class="s2">&quot;4th Street&quot;</span><span class="p">,</span>
      <span class="nt">&quot;city&quot;</span><span class="p">:</span><span class="s2">&quot;Lawrence&quot;</span><span class="p">,</span>
      <span class="nt">&quot;state&quot;</span><span class="p">:</span><span class="s2">&quot;KS&quot;</span><span class="p">,</span>
      <span class="nt">&quot;zip&quot;</span><span class="p">:</span><span class="s2">&quot;66045&quot;</span>
   <span class="p">}</span>
<span class="p">}</span></code></pre></figure></p>

<p>What I've seen less of, and what this post will highlight, is the Serializer library's ability to take XML (and JSON) and transform it back into an object graph.</p>

<h3>Data exchange formats and composite data types</h3>

<p>Serializing PHP objects to JSON or XML is painless because the rich data types encapsulated by a PHP object are transformed from their PHP data constructs, which allow composing rich "composite types" of data (e.g. your domain objects) made up of primitive types (e.g. strings, integers, booleans, etc), into a format like JSON or XML that is limited to only primitive data types.</p>

<p>Having a small number of primitive data types is an advantage of a data exchange format like JSON or XML. They are easy to create and allow high-level languages to work with data in their native language constructs before decomposing that data back into a data exchange format to allow another application to use it.</p>

<p>To take advantage of the exchange format and rebuild our feature-rich PHP objects, we must provide the Serializer service more explicit details about what data types our domain objects expect each property to use.</p>

<p>You've probably seen PHPDoc annotations like <code>@var string</code> or <code>@var \DateTime</code> on PHP objects. <a href="http://www.phpdoc.org">phpDocumentor</a> and most IDEs will parse and use these for data completion, but the Serializer component uses its own annotations that provide a bit more detail.</p>

<h3>Annotating object properties with Serializer Types</h3>

<p>Your <code>Acme\DemoBundle\Entity\User</code> object probably has a lot of things it can do in the form of methods, and likely has several relationships to other objects. We want to take advantage of that rich domain model and the behavior of those objects once we receive data from our third-party API. Not only that but we want to hydrate those model objects without writing a bunch of boiler-plate code.</p>

<p>With a little additional configuration, we can allow the JMS Serializer to take JSON or XML and properly deserialize it back into PHP domain objects.</p>

<p>Here's our basic <code>User</code> object. I have omitted all of the normal behavior methods and all getters/setters for brevity, so we'll just use public properties. Chances are your User object would have a lot more methods and use private properties exposed by getters and setters.</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="k">namespace</span> <span class="nx">Acme\DemoBundle\Entity</span><span class="p">;</span><span class="o">&lt;/</span><span class="nx">p</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="k">use</span> <span class="nx">Doctrine\Common\Collections\ArrayCollection</span><span class="p">;</span><span class="o">&lt;/</span><span class="nx">p</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="k">class</span> <span class="nc">User</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nv">$firstName</span><span class="p">;</span>
    <span class="k">public</span> <span class="nv">$lastName</span><span class="p">;</span>
    <span class="k">public</span> <span class="nv">$logins</span><span class="p">;</span>
    <span class="k">public</span> <span class="nv">$lastLogin</span><span class="p">;</span>
    <span class="k">public</span> <span class="nv">$address</span><span class="p">;</span>
    <span class="k">public</span> <span class="nv">$friends</span><span class="p">;</span><span class="o">&lt;/</span><span class="nx">p</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">pre</span><span class="o">&gt;&lt;</span><span class="nx">code</span><span class="o">&gt;</span><span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nv">$this</span><span class="o">-&amp;</span><span class="nx">gt</span><span class="p">;</span><span class="nx">address</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Address</span><span class="p">();</span>
    <span class="nv">$this</span><span class="o">-&amp;</span><span class="nx">gt</span><span class="p">;</span><span class="nx">friends</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ArrayCollection</span><span class="p">();</span>
<span class="p">}</span>
<span class="o">&lt;/</span><span class="nx">code</span><span class="o">&gt;&lt;/</span><span class="nx">pre</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="p">}</span></code></pre></figure></p>

<p>Let's say your company stores its user data on another server and exposes it via an HTTP API to your custom application. You decide to fetch an XML representation of that user resource via a request <code>GET http://someapi.com/users/10</code> and the response body might look like this:</p>

<p><figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span></span><span class="ni">&amp;lt;</span>?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
<span class="nt">&lt;result&gt;</span>
  <span class="nt">&lt;first_name&gt;</span>John<span class="nt">&lt;/first_name&gt;</span>
  <span class="nt">&lt;last_name&gt;</span>Kary<span class="nt">&lt;/last_name&gt;</span>
  <span class="nt">&lt;logins&gt;</span>5<span class="nt">&lt;/logins&gt;</span>
  <span class="nt">&lt;last_login&gt;</span>2013-07-21T00:55:59-0500<span class="nt">&lt;/last_login&gt;</span>
  <span class="nt">&lt;address&gt;</span>
    <span class="nt">&lt;number&gt;</span>555<span class="nt">&lt;/number&gt;</span>
    <span class="nt">&lt;street&gt;</span>4th Street<span class="nt">&lt;/street&gt;</span>
    <span class="nt">&lt;city&gt;</span>Lawrence<span class="nt">&lt;/city&gt;</span>
    <span class="nt">&lt;state&gt;</span>KS<span class="nt">&lt;/state&gt;</span>
    <span class="nt">&lt;zip&gt;</span>66045<span class="nt">&lt;/zip&gt;</span>
  <span class="nt">&lt;/address&gt;</span>
  <span class="nt">&lt;friends&gt;</span>
    <span class="nt">&lt;friend&gt;</span>
      <span class="nt">&lt;first_name&gt;</span>Chris<span class="nt">&lt;/first_name&gt;</span>
      <span class="nt">&lt;last_name&gt;</span>Escalante<span class="nt">&lt;/last_name&gt;</span>
      <span class="nt">&lt;logins&gt;</span>3<span class="nt">&lt;/logins&gt;</span>
      <span class="nt">&lt;last_login&gt;</span>2013-07-11T12:22:41-0500<span class="nt">&lt;/last_login&gt;</span>
    <span class="nt">&lt;/friend&gt;</span>
    <span class="nt">&lt;friend&gt;</span>
      <span class="nt">&lt;first_name&gt;</span>Dustin<span class="nt">&lt;/first_name&gt;</span>
      <span class="nt">&lt;last_name&gt;</span>Gordon<span class="nt">&lt;/last_name&gt;</span>
      <span class="nt">&lt;logins&gt;</span>1<span class="nt">&lt;/logins&gt;</span>
      <span class="nt">&lt;last_login&gt;</span>2013-06-26T14:16:33-0500<span class="nt">&lt;/last_login&gt;</span>
    <span class="nt">&lt;/friend&gt;</span>
  <span class="nt">&lt;/friends&gt;</span>
<span class="nt">&lt;/result&gt;</span></code></pre></figure></p>

<p>Given this response, you probably thought you would try using JMS Serializer to deserialize this XML into a User object. You probably discovered the <code>SerializerInterface-&gt;deserialize($data, $type, $format)</code> method, passed in your XML data, provided the fully-qualified class name to your target object and told it to use the XML format:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="s1">&#39;jms.serializer&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">deserialize</span><span class="p">(</span><span class="nv">$xml</span><span class="p">,</span> <span class="s1">&#39;Acme\DemoBundle\Entity\User&#39;</span><span class="p">,</span> <span class="s1">&#39;xml&#39;</span><span class="p">);</span></code></pre></figure></p>

<p>If you tried this as-is you would be met with a <code>JMS\Serializer\Exception\RuntimeException</code> with an exception message like this:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="x">You must define a type for Acme\DemoBundle\Entity\User::$firstName.</span></code></pre></figure></p>

<p>We must tell the Serializer what format or data type to use when translating an XML node like <code>&lt;first_name&gt;John&lt;/first_name&gt;</code> back onto our User object's property <code>public $firstName</code>.</p>

<p>Let's annotate our properties to parse this XML. Be sure to reference the <a href="http://jmsyst.com/libs/serializer/master/reference/annotations">official Annotation documentation</a> for all possible annotations:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="k">namespace</span> <span class="nx">Acme\DemoBundle\Entity</span><span class="p">;</span><span class="o">&lt;/</span><span class="nx">p</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="k">use</span> <span class="nx">Doctrine\Common\Collections\ArrayCollection</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">JMS\Serializer\Annotation</span> <span class="k">as</span> <span class="nx">JMS</span><span class="p">;</span><span class="o">&lt;/</span><span class="nx">p</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="k">class</span> <span class="nc">User</span>
<span class="p">{</span>
    <span class="o">/&lt;</span><span class="nx">em</span><span class="o">&gt;*</span>
     <span class="o">*</span> <span class="o">@</span><span class="nx">JMS\Type</span><span class="p">(</span><span class="s2">&quot;string&quot;</span><span class="p">)</span>
     <span class="o">&lt;/</span><span class="nx">em</span><span class="o">&gt;/</span>
    <span class="k">public</span> <span class="nv">$firstName</span><span class="p">;</span><span class="o">&lt;/</span><span class="nx">p</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">pre</span><span class="o">&gt;&lt;</span><span class="nx">code</span><span class="o">&gt;/**</span>
 <span class="o">*</span> <span class="o">@</span><span class="nx">JMS\Type</span><span class="p">(</span><span class="s2">&quot;string&quot;</span><span class="p">)</span>
 <span class="o">*/</span>
<span class="k">public</span> <span class="nv">$lastName</span><span class="p">;</span>

<span class="sd">/**</span>
<span class="sd"> * Number of times has logged in.</span>
<span class="sd"> * @JMS\Type(&quot;integer&quot;)</span>
<span class="sd"> */</span>
<span class="k">public</span> <span class="nv">$logins</span><span class="p">;</span>

<span class="sd">/**</span>
<span class="sd"> * Last time logged in using ISO 8601 format.</span>
<span class="sd"> * @JMS\Type(&quot;DateTime&amp;lt;&#39;Y-m-d\TH:i:sO&#39;&amp;gt;&quot;)</span>
<span class="sd"> */</span>
<span class="k">public</span> <span class="nv">$lastLogin</span><span class="p">;</span>

<span class="sd">/**</span>
<span class="sd"> * @JMS\Type(&quot;Acme\DemoBundle\Entity\Address&quot;)</span>
<span class="sd"> */</span>
<span class="k">public</span> <span class="nv">$address</span><span class="p">;</span>

<span class="sd">/**</span>
<span class="sd"> * @JMS\Type(&quot;ArrayCollection&amp;lt;Acme\DemoBundle\Entity\User&amp;gt;&quot;)</span>
<span class="sd"> * @JMS\XmlList(entry=&quot;friend&quot;)</span>
<span class="sd"> */</span>
<span class="k">public</span> <span class="nv">$friends</span><span class="p">;</span>

<span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nv">$this</span><span class="o">-&amp;</span><span class="nx">gt</span><span class="p">;</span><span class="nx">address</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Address</span><span class="p">();</span>
    <span class="nv">$this</span><span class="o">-&amp;</span><span class="nx">gt</span><span class="p">;</span><span class="nx">friends</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ArrayCollection</span><span class="p">();</span>
<span class="p">}</span>
<span class="o">&lt;/</span><span class="nx">code</span><span class="o">&gt;&lt;/</span><span class="nx">pre</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="p">}</span></code></pre></figure></p>

<p>The annotations we're using above:</p>

<ul>
<li><a href="http://jmsyst.com/libs/serializer/master/reference/annotations#type">@Type</a></li>
<li><a href="http://jmsyst.com/libs/serializer/master/reference/annotations#xmllist">@XmlList</a></li>
</ul>


<p>We can now take that XML response and deserialize it back into a rich User object. Here's the full code embedded in a controller where you might make your request to the HTTP API and do something with the XML response:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="k">namespace</span> <span class="nx">Acme\DemoBundle\Controller</span><span class="p">;</span><span class="o">&lt;/</span><span class="nx">p</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="k">use</span> <span class="nx">Symfony\Bundle\FrameworkBundle\Controller\Controller</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Sensio\Bundle\FrameworkExtraBundle\Configuration\Route</span><span class="p">;</span><span class="o">&lt;/</span><span class="nx">p</span><span class="o">&gt;</span>

<span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="k">class</span> <span class="nc">DemoController</span> <span class="k">extends</span> <span class="nx">Controller</span>
<span class="p">{</span>
    <span class="o">/&lt;</span><span class="nx">em</span><span class="o">&gt;*</span>
     <span class="o">*</span> <span class="o">@</span><span class="nx">Route</span><span class="p">(</span><span class="s2">&quot;/&quot;</span><span class="p">,</span> <span class="nx">name</span><span class="o">=</span><span class="s2">&quot;deserialize&quot;</span><span class="p">)</span>
     <span class="o">&lt;/</span><span class="nx">em</span><span class="o">&gt;/</span>
    <span class="k">public</span> <span class="k">function</span> <span class="nf">helloAction</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// Assume you get your XML from some third-party</span>
        <span class="nv">$xml</span> <span class="o">=</span> <span class="o">&amp;</span><span class="nx">lt</span><span class="p">;</span><span class="o">&amp;</span><span class="nx">lt</span><span class="p">;</span><span class="o">&lt;</span><span class="nx">EOT</span>
<span class="o">&lt;?</span><span class="nx">xml</span> <span class="nx">version</span><span class="o">=</span><span class="s2">&quot;1.0&quot;</span> <span class="nx">encoding</span><span class="o">=</span><span class="s2">&quot;UTF-8&quot;</span><span class="cp">?&gt;</span><span class="x"></span>
<span class="x">&lt;result&gt;</span>
<span class="x">  &lt;first_name&gt;John&lt;/first_name&gt;</span>
<span class="x">  &lt;last_name&gt;Kary&lt;/last_name&gt;</span>
<span class="x">  &lt;logins&gt;5&lt;/logins&gt;</span>
<span class="x">  &lt;last_login&gt;2013-07-21T00:55:59-0500&lt;/last_login&gt;</span>
<span class="x">  &lt;address&gt;</span>
<span class="x">    &lt;number&gt;555&lt;/number&gt;</span>
<span class="x">    &lt;street&gt;4th Street&lt;/street&gt;</span>
<span class="x">    &lt;city&gt;Lawrence&lt;/city&gt;</span>
<span class="x">    &lt;state&gt;KS&lt;/state&gt;</span>
<span class="x">    &lt;zip&gt;66045&lt;/zip&gt;</span>
<span class="x">  &lt;/address&gt;</span>
<span class="x">  &lt;friends&gt;</span>
<span class="x">    &lt;friend&gt;</span>
<span class="x">      &lt;first_name&gt;Chris&lt;/first_name&gt;</span>
<span class="x">      &lt;last_name&gt;Escalante&lt;/last_name&gt;</span>
<span class="x">      &lt;logins&gt;3&lt;/logins&gt;</span>
<span class="x">      &lt;last_login&gt;2013-07-11T12:22:41-0500&lt;/last_login&gt;</span>
<span class="x">    &lt;/friend&gt;</span>
<span class="x">    &lt;friend&gt;</span>
<span class="x">      &lt;first_name&gt;Dustin&lt;/first_name&gt;</span>
<span class="x">      &lt;last_name&gt;Gordon&lt;/last_name&gt;</span>
<span class="x">      &lt;logins&gt;1&lt;/logins&gt;</span>
<span class="x">      &lt;last_login&gt;2013-06-26T14:16:33-0500&lt;/last_login&gt;</span>
<span class="x">    &lt;/friend&gt;</span>
<span class="x">  &lt;/friends&gt;</span>
<span class="x">&lt;/result&gt;</span>
<span class="x">EOT;&lt;/p&gt;</span>

<span class="x">&lt;pre&gt;&lt;code&gt;    $user = $this-&amp;gt;get(&#39;jms_serializer&#39;)-&amp;gt;deserialize($xml, &#39;Acme\DemoBundle\Entity\User&#39;, &#39;xml&#39;);</span>

<span class="x">    var_dump($user);</span>
<span class="x">    exit;</span>
<span class="x">}</span>
<span class="x">&lt;/code&gt;&lt;/pre&gt;</span>

<span class="x">&lt;p&gt;}</span></code></pre></figure></p>

<p>I'm using var_dump here to show exactly how the data appears when hydrated onto the User object:</p>

<div class="highlight"><pre><code class="language-php" data-lang="php">object(Acme\DemoBundle\Entity\User)[416]
  public 'firstName' => string 'John' (length=4)
  public 'lastName' => string 'Kary' (length=4)
  public 'logins' => int 5
  public 'lastLogin' => 
    object(DateTime)[436]
      public 'date' => string '2013-07-21 00:55:59' (length=19)
      public 'timezone_type' => int 1
      public 'timezone' => string '-05:00' (length=6)
  public 'address' => 
    object(Acme\DemoBundle\Entity\Address)[434]
      public 'number' => string '555' (length=3)
      public 'street' => string '4th Street' (length=10)
      public 'city' => string 'Lawrence' (length=8)
      public 'state' => string 'KS' (length=2)
      public 'zip' => string '66045' (length=5)
  public 'friends' => 
    object(Doctrine\Common\Collections\ArrayCollection)[450]
      private '_elements' => 
        array (size=2)
          0 => 
            object(Acme\DemoBundle\Entity\User)[455]
              ...
          1 => 
            object(Acme\DemoBundle\Entity\User)[454]
              ...
</code></pre></div>


<p>We can now work with our User object and it can boast all of its rich behavior and relationships with other objects!</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Now Powered By Jekyll]]></title>
            <link>http://johnkary.net/blog/now-powered-by-jekyll/</link>
            <comments>http://johnkary.net/blog/now-powered-by-jekyll/#disqus_thread</comments>
            <pubDate>Sun, 16 Dec 2012 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[jekyll]]></category><category><![CDATA[wordpress]]></category>
            <guid>http://johnkary.net/blog/now-powered-by-jekyll</guid>
            <description><![CDATA[A few of my previous posts have been fortunate enough to become front-page worthy on Hacker News and /r/programming. But the rush of traffic toppled my WordPress blog. So I toppled WordPress and replaced it with Jekyll.]]></description>
            <content:encoded><![CDATA[<p>My previous blog post on <code>git add -p</code> hit the front page of <a href="https://news.ycombinator.com/">Hacker News</a> and <a href="http://www.reddit.com/r/programming">/r/programming</a> and the huge influx of traffic brought down my blog. This had happened once before, ironically when a previous git post of mine hit HN, but I thought <a href="https://twitter.com/tidrion">Chris</a> and I had prevented it from happening again by using the WP-Cache WordPress plugin.</p>

<p>Well looks like those sites sent so much traffic our 512MB server running Apache + MySQL + WP-Cache still couldn't keep up.</p>

<p>That's impressive considering when the same post was on the front page of <a href="http://reddit.com/r/programming">/r/programming</a> it did about 20,000 views all together, 15,000 of which during one day. I guess front page of HN at noon CST on a Monday lands you a lot of traffic really fast.</p>

<h3>Peace out WordPress</h3>

<p>So in the interest of not investing more time battling outdated WordPress versions and a bunch of dynamic functionality I simply didn't need, and a desire to learn a bit more Ruby, I've decided to move this blog and the rest of my personal site to be generated by <a href="https://github.com/mojombo/jekyll">Jekyll</a>.</p>

<p>This now means all of my posts are written in a text editor, formatted in Markdown and stored in a git repository. Deployment is done via a <code>post-merge</code> hook from my local dev repository to my remote server via rsync.</p>

<p>My content is no longer held hostage, holed up in some remote database. It's in plain-text, in a version control repository, where it belongs.</p>

<h3>Migrating WordPress to Jekyll</h3>

<p>WordPress has built-in export functionality, which dumps all of its pages, posts and comments to XML. It's conveniently accessible from the admin panel at <code>/wp-admin/export.php</code>.</p>

<p>The Jekyll docs have a section on <a href="https://github.com/mojombo/jekyll/wiki/blog-migrations">Blog Migrations</a>. I followed the instructions to exchange my newly-generated <code>wordpress.xml</code> into freshly-minted static HTML pages in a format Jekyll expects.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">gem install hpricot</span>
<span class="go">ruby -rubygems -e &#39;require &quot;jekyll/migrators/wordpressdotcom&quot;; Jekyll::WordpressDotCom.process(&quot;wordpress.xml&quot;)&#39;</span></code></pre></figure></p>

<p>I then leveraged <a href="http://johnmacfarlane.net/pandoc/">Pandoc</a> to convert the resulting HTML files to straight Markdown.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">cd ~/Sites/johnkary.github.com/_posts</span>
<span class="go">pandoc --from=html --to=markdown --no-wrap --output=2009-12-08-my-post-title.md 2009-12-08-my-post-title.html</span></code></pre></figure></p>

<p>The Pandoc-generated Markdown files were very accurate for the most part. The only fail was I had to re-split the paragraph text because the original Jekyll import dumped my paragraphs without <code>&lt;p&gt;</code> tags, so Pandoc just merged that text together. This was a result of how the text was stored in the WordPress database. I also had to clean up some poor formatting from some older posts, but nothing major for my 20 blog entries.</p>

<h3>Development Mode</h3>

<p>When I'm developing on my site, I run the built-in Jekyll web server then load the site in my browser at http://0.0.0.0:4000</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">cd ~/Sites/johnkary.github.com</span>
<span class="go">jekyll --server --auto</span></code></pre></figure></p>

<p><code>--server</code> tells Jekyll to run its WEBrick web server (instead of just generating the site).</p>

<p><code>--auto</code> tells Jekyll to watch my source files for changes, and regenerate my site files on save. So if I'm writing a new blog post or editing CSS and save my file, Jekyll regenerates the corresponding static file.</p>

<h3>Liquid Templating Language</h3>

<p>Jekyll uses the <a href="http://liquidmarkup.org/">Liquid Templating Language</a>. I felt very at home with it right away because it's basically exactly like <a href="http://twig.sensiolabs.org/doc/templates.html">Twig Templates</a>. And Twig is inspired by Jinja2 templates, which uses the same syntax. I don't know who was "first" in all of this, but there was no additional learning curve for me in learning the templating syntax.</p>

<h3>Syntax Highlighting</h3>

<p>Jekyll has support for the great syntax highlighting Python library <a href="http://pygments.org/">Pygments</a>, which probably supports every language you know.</p>

<p>It supports PHP, but I had to dig around a bit to find its PhpLexer option <code>startinline</code>. If the <code>startinline</code> option is not given, Pygments will only start highlighting after it finds <code>&lt;?php</code>. I don't use <code>&lt;?php</code> in my code examples, so my highlighting wasn't working until I found <a href="https://github.com/mojombo/jekyll/issues/31">this Jekyll issue</a> introducing <code>startinline</code> functionality.</p>

<p><figure class="highlight"><pre><code class="language-jinja" data-lang="jinja"><span></span><span class="cp">{%</span> <span class="k">highlight</span> <span class="nv">php</span> <span class="cp">%}</span><span class="x"></span>
<span class="x">// No source highlighting</span>
<span class="x">$name = $person-&gt;getName();</span>
<span class="cp">{%</span> <span class="k">endhighlight</span> <span class="cp">%}</span><span class="x">&lt;/p&gt;</span>

<span class="x">&lt;p&gt;</span><span class="cp">{%</span> <span class="k">highlight</span> <span class="nv">php</span> <span class="nv">startinline</span> <span class="cp">%}</span><span class="x"></span>
<span class="x">// Source highlighting without opening PHP tag</span>
<span class="x">$name = $person-&gt;getName();</span>
<span class="cp">{%</span> <span class="k">endhighlight</span> <span class="cp">%}</span><span class="x"></span></code></pre></figure></p>

<h3>Redirects From Old Site</h3>

<p>A number of my blog posts have been picked up on various link portals over the years, and people regularly find my posts using Google. If I took my new blogging engine and gave no care to redirect to the new post URL I would lose my search engine rankings. Google would likely see my new posts as simply new content with no credibility.</p>

<p>Instead I'm choosing a two-headed approach:</p>

<ol>
<li>Use Apache's <code>.htaccess</code> file to explicitly use <code>301 Redirects</code> to the new URLs. This will tell Google and other crawlers the page has permanently moved. I have then instructed the Google crawler to re-crawl my site to pickup the new URLs. Given a few weeks to a month, my new URLs should reflect in search engines.</li>
<li>Use a Jekyll plugin called <a href="https://github.com/tsmango/jekyll_alias_generator">alias_generator</a> to generate an <code>index.html</code> page at the old URL which has a meta-redirect to the new page.</li>
</ol>


<p>Yes, a meta-redirect is not ideal and isn't good practice. In the long-term I may move my site to be powered by <a href="http://pages.github.com/">GitHub Pages</a>, which doesn't support <code>.htaccess</code> or other means of redirects. It's at this point that anyone still linking to my old posts can still find their way to the new path.</p>

<p>This alias_generator plugin parses an <code>alias:</code> key in the YAML Front Matter, which is just some YAML in the heading of every Jekyll template file. This per-file configuration allows configuring how the page is rendered.</p>

<p>Installing this custom plugin is easy. Just copy it into <code>./_plugins/alias_generator.rb</code> and Jekyll will pick up any file ending in <code>./_plugins/*.rb</code> when compiling.</p>

<p>To setup the "redirect", let's use my example blog post previously at <a href="http://johnkary.net/git-add-p-the-most-powerful-git-feature-youre-not-using-yet/">http://johnkary.net/git-add-p-the-most-powerful-git-feature-youre-not-using-yet/</a>. I can use the following <code>alias:</code> key and Jekyll will generate an HTML page at <code>./git-add-p-the-most-powerful-git-feature-youre-not-using-yet/index.html</code> which redirects to the new post's URL.</p>

<p><figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span></span><span class="l l-Scalar l-Scalar-Plain">layout</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">post</span>
<span class="l l-Scalar l-Scalar-Plain">title</span><span class="p p-Indicator">:</span> <span class="err">!</span> <span class="s">&quot;git</span><span class="nv"> </span><span class="s">add</span><span class="nv"> </span><span class="s">-p:</span><span class="nv"> </span><span class="s">The</span><span class="nv"> </span><span class="s">most</span><span class="nv"> </span><span class="s">powerful</span><span class="nv"> </span><span class="s">git</span><span class="nv"> </span><span class="s">feature</span><span class="nv"> </span><span class="s">you&#39;re</span><span class="nv"> </span><span class="s">not</span><span class="nv"> </span><span class="s">using</span><span class="nv"> </span><span class="s">yet&quot;</span>
<span class="l l-Scalar l-Scalar-Plain">status</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">publish</span>
<span class="l l-Scalar l-Scalar-Plain">type</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">post</span>
<span class="l l-Scalar l-Scalar-Plain">published</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="l l-Scalar l-Scalar-Plain">alias</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">/git-add-p-the-most-powerful-git-feature-youre-not-using-yet</span></code></pre></figure></p>

<p>The plugin then sticks an HTML file at the path specified and anyone encountering that page will be forwarded to the new URL.</p>

<p><figure class="highlight"><pre><code class="language-html" data-lang="html"><span></span><span class="ni">&amp;lt;</span>!DOCTYPE html&gt;
<span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;canonical&quot;</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;/2012/10/30/git-add-p-the-most-powerful-git-feature-youre-not-using-yet.html&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">meta</span> <span class="na">http-equiv</span><span class="o">=</span><span class="s">&quot;content-type&quot;</span> <span class="na">content</span><span class="o">=</span><span class="s">&quot;text/html; charset=utf-8&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">meta</span> <span class="na">http-equiv</span><span class="o">=</span><span class="s">&quot;refresh&quot;</span> <span class="na">content</span><span class="o">=</span><span class="s">&quot;0;url=/2012/10/30/git-add-p-the-most-powerful-git-feature-youre-not-using-yet.html&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span></code></pre></figure></p>

<h3>Moving Comments to Disqus</h3>

<p>All of my old comments were stored in WordPress. But now I have no WordPress.</p>

<p><a href="http://disqus.com/">Disqus</a> provides comments as a service via a JavaScript widget. They also provide <a href="http://help.disqus.com/customer/portal/articles/466255-exporting-comments-from-wordpress-to-disqus">good instructions</a> for abandoning WordPress comments.</p>

<p>I chose the "Manual Import" method because frankly I didn't want to bother installing the plugin. I used my previous <code>wordpress.xml</code> dump from before and uploaded it through their site. The comments imported correctly <em>but at the old WordPress URL paths.</em></p>

<p>The problem here is, I moved my blog posts from being at the root of my domain (e.g. /my-title-here) to instead live under /blog/my-title-here.</p>

<p>At time of writing, Disqus allow you to address this issue from its Dashboard by instructing its spider to crawl your domain and process any 301 Redirects you have setup. So my <code>.htaccess</code> redirects have caught those and the URLs associated with my old comments are now on their new respective pages.</p>

<p>Well done, Disqus.</p>

<h3>Source Code Available</h3>

<p>The source code for this site is available on GitHub: <a href="https://github.com/johnkary/johnkary.net">https://github.com/johnkary/johnkary.net</a></p>

<h3>That's It!</h3>

<p>Overall I'm really happy with this new setup. I feel much more in control of my site, and am much more comfortable writing into a text editor with vim bindings than a WordPress textarea.</p>

<p>I looked at <a href="http://octopress.org/">Octopress</a> but felt it did too much for what I wanted to accomplish. I wanted a more micro-approach.</p>

<p>I may also redesign the site at some point in the future, maybe to make it responsive, but right now double-tapping on the content body it's still very readable and focuses only on the content.</p>

<p>If you see any problems with my site, please ping me on Twitter <a href="https://twitter.com/johnkary">@johnkary</a></p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[git add -p: The most powerful git feature you're not using yet]]></title>
            <link>http://johnkary.net/blog/git-add-p-the-most-powerful-git-feature-youre-not-using-yet/</link>
            <comments>http://johnkary.net/blog/git-add-p-the-most-powerful-git-feature-youre-not-using-yet/#disqus_thread</comments>
            <pubDate>Tue, 30 Oct 2012 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[git]]></category><category><![CDATA[tutorial]]></category>
            <guid>http://johnkary.net/blog/git-add-p-the-most-powerful-git-feature-youre-not-using-yet</guid>
            <description><![CDATA[The Pragmatic Programmer advocates you should know your editor inside and out. So why don’t you know your version control system just as well? Discover git add “patch mode” and learn how to make more concisely crafted commits leading to a cleaner git history and more friends.]]></description>
            <content:encoded><![CDATA[<blockquote><p><strong>Update January 20, 2014 -</strong> This old post from 2012 has again become popular on <a href="https://news.ycombinator.com/item?id=7089399">Hacker News</a>. Since first publishing this article, I've learned that the way I presented editing hunks in the second video, where I show how to edit the line spans at the top of the diff, is both not very efficient and rarely necessary. Hopefully the rest of that video is still useful.</p></blockquote>

<p><a href="http://gitscm.org/">git</a> and GitHub have revolutionized not only how I do development, but how we developers share code.</p>

<p>I have two tools I need to do software development: an editor and version control.</p>

<p><a href="http://pragprog.com/the-pragmatic-programmer">The Pragmatic Programmer</a> advocates you should know your editor inside and out. <strong>So why don't you know your version control system just as well?</strong></p>

<h3>Patch Mode</h3>

<p>If you use git, you've used the command <code>git add</code>. But do you know about git add's "patch mode" using <code>git add -p</code> ?</p>

<p>Patch mode allows you to stage <em>parts</em> of a changed file, instead of the entire file. This allows you to make concise, well-crafted commits that make for an easier to read history.</p>

<p>Since I learned about it a year or so ago, patch mode has taken my git usage to another level. It's one of the most powerful git commands, right up there with rebasing, but much less dangerous!</p>

<h3>Screencasts</h3>

<p>I have recorded two 10-minute screencasts about how I use git add's patch mode. And I want to share them with you for free.</p>

<p>In the first video I walk you through why patch mode is something <strong>you should be using today</strong>, then demonstrate its basic features.</p>

<p>In the second video I talk through the dark art of editing hunks. Even some of the most knowledgeable git users I know have struggled with this! To really master patch mode you will want to know how to edit hunks. Never fear "patch does not apply" again!</p>

<p>I hope that after watching you will be armed with a new skill you can start using <strong>right away</strong> and begin to know git at a deeper level.</p>

<h3><a href="http://www.youtube.com/embed/Wl0NfWYrvlY">Intro to git add patch mode tutorial</a></h3>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/Wl0NfWYrvlY" frameborder="0" allowfullscreen></iframe></div>


<h3><a href="http://www.youtube.com/embed/1tqMjJeyKpw">One way to edit hunks in git add patch mode</a></h3>

<div class="embed-container"><iframe src="https://www.youtube.com/embed/1tqMjJeyKpw" frameborder="0" allowfullscreen></iframe></div>



]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Developers: We are no longer Apple's target market]]></title>
            <link>http://johnkary.net/blog/developers-we-are-no-longer-apples-target-market/</link>
            <comments>http://johnkary.net/blog/developers-we-are-no-longer-apples-target-market/#disqus_thread</comments>
            <pubDate>Wed, 25 Jul 2012 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[apple]]></category><category><![CDATA[hardware]]></category><category><![CDATA[software]]></category>
            <guid>http://johnkary.net/blog/developers-we-are-no-longer-apples-target-market</guid>
            <description><![CDATA[Over the last few years, especially since the release of Lion in July 2011, there is an air of neglect floating amongst the development community that use Apple hardware running OS X as their primary workstation. Many developers feel Apple is not focused on their best interests as developers and are frustrated with new Apple products.<br><br>When Apple released their Q3 Financial Report yesterday, I was finally able to put statistics to backup the feeling of neglect.]]></description>
            <content:encoded><![CDATA[<p>Today Apple released the next version of their operating system, OS X 10.8 Mountain Lion. While many <a href="http://www.macrumors.com/2012/07/25/roundup-of-os-x-mountain-lion-reviews-faster-and-smoother-incremental-bargain-at-twice-the-price/">herald it as a must-have</a>, the refinements are less revolutionary at the core operating system level, and more focused on integration with iOS-based services.</p>

<p>Over the last few years, especially since the release of Lion in July 2011, there is an air of neglect floating amongst the development community that use Apple hardware running OS X as their primary workstation. Many developers feel Apple is not focused on their best interests as developers and are frustrated with new Apple products.</p>

<p>We developers spend much of our time on a laptop or desktop doing research, programming and debugging code, and testing our latest software. Our computers are our lifeblood. They become extensions of ourselves. When something about them changes that hampers our productivity or ability to do work, we get very frustrated. And then we write scathing blog posts and passive-aggressive tweets on Twitter.</p>

<h3>My New Air</h3>

<p>I recently upgraded from a mid-2008 17" MacBook Pro to a mid-2012 13" MacBook Air. The MacBook Pro I upgraded from was my first Apple machine. I loved Leopard (10.5) and Snow Leopard (10.6) and felt very at home and productive in the 4 years I used them. But the new MacBook Air dropped me right into Lion (10.7).</p>

<p>Like many before me, I bemoaned many of the small changes between Snow Leopard and Lion, mostly because many of them decreased my productivity by acting counter to how I'd been accustomed to it, or software I had previously relied on simply didn't work in Lion.</p>

<p>This was my lifeblood Apple was messing with here. This is how I make my living. I can't have a computer that I feel is working against me or takes away my ability to work efficiently.</p>

<p>Now in the 2 weeks since, I've grown accustomed to a few of Lion's nuances (I've embraced the natural scrolling, for example). But it finally clicked when I saw Apple Q3 financial reports yesterday. In it I finally had statistical evidence to backup the feelings shared in the development community that Apple doesn't prioritize OS X anymore.</p>

<h3>Back to the Mac</h3>

<p>When Lion was announced, it was unveiled to the mantra of "Back to the Mac", where Apple announced they would be taking some features from iOS and integrating them into their desktops running OS X.</p>

<p>What Apple must have seen at the time was that the barrier to entry for Apple into many consumer households was now very low. As low as a FREE subsidized iPhone from a cell phone carrier. No longer were their bold designs and refined hardware relegated to $1000 computers. General consumers could afford a free or $99 iPhone. And they did. They snatched up iPhones in droves helping make iOS the most prolific Apple software ever.</p>

<p>The <a href="http://www.macrumors.com/2012/07/24/apple-reports-results-for-q3-2012-8-8-billion-profit-on-35-billion-in-revenue/">Q3 2013 financial results</a> unveiled on July 24, 2012 tell an interesting picture. This graph by MacRumors sums up Apple's current revenue picture and how it really drives home the success of iOS-enabled devices:</p>

<div class="image">
    <a href="http://www.macrumors.com/2012/07/24/apple-reports-results-for-q3-2012-8-8-billion-profit-on-35-billion-in-revenue/"><img src="http://cdn.macrumors.com/article-new/2012/07/2q12_revenue.jpg" title="Apple's Q3 Revenue Results"></a>
</div>


<p>Most notably, look at iOS-enabled devices vs OS X-enabled devices. Here's the math:</p>

<p><strong>iOS-Enabled Devices:</strong><br/>
iPhone: 46%<br/>
iPad: 26%<br/>
iPod: 3%<br/>
= 75% of company revenue</p>

<p><strong>OS X-Enabled Devices:</strong><br/>
CPU Net Sales (MacBooks, iMacs, Mac Pros, etc)<br/>
= 14% of company revenue</p>

<p>75% of Apple revenue comes from iOS-enabled devices. <strong>75%!</strong> Roughly, for every $1 Apple brings in on MacBook or iMac sales, they bring in 5 times as much in iPhone, iPad and iPod sales. 500%!</p>

<p>As a company, where would you put your smartest engineers? Probably on the software reaching not only the majority of your customers, but likely the software reaching your first-time customers.</p>

<h3>How did Apple get here?</h3>

<p>iOS-enabled devices have exploded in the last 2 years, and Apple's shift away from developing OS X as its flagship core product have followed suit.</p>

<p>Another graph from MacRumors shows Apple's revenue by financial quarter, where we can see this transition from the start of 2009 to current mid-2012.</p>

<p>Pay specific attention to the blue area (OS X devices) compared to essentially everything above it.</p>

<div class="image">
    <a href="http://www.macrumors.com/2012/07/24/apple-reports-results-for-q3-2012-8-8-billion-profit-on-35-billion-in-revenue/"><img src="http://cdn.macrumors.com/article-new/2012/07/2q12_revenue_history.jpg" title="Apple Revenue By Quarter"></a>
</div>


<p>OS X-enabled devices were generating about half as much revenue as iOS-enabled devices in early 2009. But in 3 years since, we've seen a huge shift in where Apple's revenue stream comes from, up to the 500% we saw in the previous graph. We developers should be silly to think Apple's engineering efforts have not followed their products' revenue potential.</p>

<h3>Future of development computing</h3>

<p>As developers, iOS is not yet at the point where it can fully replace a desktop-based machine for software development. The majority of developers will continue using powerful desktop and laptop machines to do our programming.</p>

<p>Unlike the early days of Apple when the company embraced and found refuge in the hacker mentality, Apple has emerged as a consumer company thanks to the wide reach and accessibility of its iOS products.</p>

<p>As hackers and makers we must realize we are no longer Apple's target market. OS X will continue to cater to the lay-consumer to function more like the iOS device they latched onto as a gateway into the Apple product line, all the while giving developers just enough to continue building web platforms and mobile apps that perpetuate Apple's mobile platform.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[I Am Replaceable: Leaving my job at KU]]></title>
            <link>http://johnkary.net/blog/i-am-replaceable-leaving-my-job-at-ku/</link>
            <comments>http://johnkary.net/blog/i-am-replaceable-leaving-my-job-at-ku/#disqus_thread</comments>
            <pubDate>Mon, 23 Jul 2012 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[inspiration]]></category>
            <guid>http://johnkary.net/blog/i-am-replaceable-leaving-my-job-at-ku</guid>
            <description><![CDATA[I’m not good at quitting things. But I knew someday I would have to quit a job for reasons beyond, “I’m moving to go to school” or “I graduated and am taking a job in my new profession” or some other natural progression from one life stage to another.<br><br>But Friday, July 20, 2012 was my last official day as an employee of Information Technology at the University of Kansas.]]></description>
            <content:encoded><![CDATA[<p>I'm not good at quitting things. But I knew someday I would have to quit a job for reasons beyond, "I'm moving to go to school" or "I graduated and am taking a job in my new profession" or some other natural progression from one life stage to another.</p>

<p>But Friday, July 20, 2012 was my last official day as an employee of Information Technology at the University of Kansas. I had worked at KU within the same group for almost 8 years (although the group changed drastically over the time I was a part of it, even as it continues to change.)</p>

<p>I started in late 2004 as a student web developer, was hired as a full-time programmer in 2007, and was promoted into a programming leadership position in 2008. In the 4 years since, I worked tirelessly to mold our group of cowboy coders into a modern software development team.</p>

<p>I dedicated a lot of time to establishing high standards for quality within the group, which the team was able to meet. Every developer in the group, including me, came a long way to where they are now, and I hope that even though I will no longer be part of the group that the standard for quality will rise even higher.</p>

<h3>Why are you leaving?</h3>

<p>My old group's primary responsibilities had both shifted and greatly expanded within the year prior to my departure as a result of both changes in IT leadership and in initiatives demanded as part of a push for efficiency within the greater University.</p>

<p>These new initiatives left even less time dedicated to development work and instead involved a lot more end-user support for various web development and the shared-web hosting platform we offer. Even then, the development work our team was tasked with (building out a campus-wide Drupal-based content management system) I did not find particularly exciting nor rewarding.</p>

<p>I gave it a chance for 6 months, but my suspicions were confirmed that it was time to move on. There is certainly no shortage in demand for application development, and I have been fortunate enough to have been offered a few new opportunities.</p>

<h3>Where are you going?</h3>

<p>For the immediate future I will be involved in various freelance/contract projects. I actually have a 9-month contract with the KU's Applied English Center to take their 37-year old database application written in Visual FoxPro and modernize it as a web application built on the Symfony2 framework.</p>

<p>I will also continue my long-time contract work with RapidHire, LLC, where my custom web application plays a part in allowing trucking companies to quickly qualify and hire new over-the-road truck drivers.</p>

<p>It's a strange feeling&hellip; for the time being I am actually working in my old cubicle at KU as part of my KU-based contract. I left on Friday, and here it is Monday, and I'm back in the same environment, still surrounded by all of my previous teammates. I hear their conversations about the projects we worked on before I left, and I could even verbally answer some of their questions, but my duties and paycheck now come from an entirely different place, so I must focus on my new project.</p>

<p>Honestly, this still all feels surreal. <a href="https://twitter.com/sivers">Derek Sivers</a> sums up my feelings perfectly in his book, "Anything You Want", (and in <a href="http://sivers.org/done">this post on his blog</a>) where he describes his feelings surrounding selling his company CDBaby, which he grew from being self-employeed to 85 employees and millions in CD sales:</p>

<blockquote><p>I realized that the bigger learning and growing challenge for me was letting go, not staying on.</p></blockquote>

<p>My previous group at KU will continue to evolve and grow, and I wish them all great success. They are in good hands, and I could not have asked for a better manager in Matt Garrett, who gave me every opportunity to succeed and embraced almost every suggestion in how we could improve the team's abilities, our development practices and the greater IT organization.</p>

<p>And if I achieved my goals while I was in KU IT, I will be replaceable.</p>

<p>If you are interested in hiring me for contract work or a potential full-time position, I can be reached at john at johnkary dot net.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Color temperature and why I don't yet own an iPad]]></title>
            <link>http://johnkary.net/blog/color-temperature-and-why-i-dont-yet-own-an-ipad/</link>
            <comments>http://johnkary.net/blog/color-temperature-and-why-i-dont-yet-own-an-ipad/#disqus_thread</comments>
            <pubDate>Fri, 16 Mar 2012 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[hardware]]></category>
            <guid>http://johnkary.net/blog/color-temperature-and-why-i-dont-yet-own-an-ipad</guid>
            <description><![CDATA[Like some of you, I have not yet caved and bought an iPad. Or any other tablet device, for that matter. But given that “the new” third-generation iPad was officially made available at 8:00AM this morning, that might change soon.<br><br>But even with its revolutionary display panel, I’m still reluctant to buy for one small, but very significant feature that’s still lacking: color temperature control.]]></description>
            <content:encoded><![CDATA[<p>Like some of you, I have not yet caved and bought an iPad. Or any other tablet device, for that matter. But given "the new" third-generation iPad was officially made available at 8:00AM this morning, that might soon change.</p>

<p>When the iPad debuted in April 2010 I didn't feel I had a use for it that justified the cost. I mean, "my laptop can do anything," I thought at the time. "Why would I want a crippled computer?" Was the world really ready for the new device Steve demoed?</p>

<p>But two years later, the tablet as a device is now a sustained product (I'm reluctant to call it "matured"), has first-class content available for it, and has carved its own niche in the device landscape. That $650 in my wallet is starting to feel mighty heavy&hellip;</p>

<h3>My device usage</h3>

<p>I currently spend most of my screen-time working from a 17" MacBook Pro: the normal 8-ish hours for my full-time employment, then after hours doing some reading, researching, personal programming projects and open-source work.</p>

<p>The iPad would mostly take over as a device for casual browsing with Instapaper, HackerNews, Twitter and RSS. It would also see the occasional movie or gaming while traveling. A single device for these purposes would allow me to focus on reading, instead of being distracted by email, code, chat and all the clutter that comes with normal work when using my laptop.</p>

<p>Much of this type of usage would happen in the late evening and into the night.</p>

<p>Yet there is one killer app I use on Mac OS that isn't natively available for iOS, but makes working in the evening exponentially more comfortable: <a href="http://justgetflux.com/">F.lux</a>.</p>

<div class="image">
    <a href="http://justgetflux.com/"><img src="/images/posts/flux-logo-lg.png" title="f.lux" width="293"></a>
</div>


<p>F.lux is a little app that runs in the background and automatically adjusts the <a href="http://en.wikipedia.org/wiki/Color_temperature">color temperature</a> of the screen according to the current position of the sun in the sky.</p>

<p>During normal daylight hours the screen is unaffected, resulting in light emitted at about 6500K, or about the same color temperature as sunlight radiating under a clear blue sky. But as the sun sets and the color of the light outside changes, F.lux gradually transitions the color temperature of the screen from 6500K to 2700K, which is closer to that of indoor incandescent tungsten lighting. This color-shift makes the laptop screen appear similar in color to your working environment, making it less jarring and easier on the eyes.</p>

<div class="image">
    <img src="/images/posts/flux-kelvin.png" title="Common light source color temperatures measured in degrees Kelvin" alt="The color appearance of various light sources can be defined in terms of color temperature, measured in kelvin (K). Northern Light/Blue Sky (8500K); Daylight Fluorescent Lamp (6400K); Clear Mercury Lamp (6000K); Clear Metal Halide Lamp (4500K); Cool White Fluorescent Lamp (4000K); Tungsten Halogen Lamp (3200K); Warm White Fluorescent Lamp (3000K); 40W Incandescent Lamp (2600K); High Pressure Sodium Lamp (2000K); Candle (1800K)" width="500">
</div>


<p>The human brain is very good at determining colors in varying lighting conditions and deciding, "that's blue" or "that's white".</p>

<p>It's so good that you often will not notice a difference in color because all other colors are contextually and equally shifted towards the blue or orange end of the spectrum depending on the light source.</p>

<p>You are likely only aware of a difference when looking at a picture and being removed from the actual experience. If you're familiar with fixing the white balance of a photo, your brain is doing exactly that, all in real time.</p>

<p>This effect is most pronounced when comparing color swatches side-by-side and deciding which one appears more blue or more orange.</p>

<div class="image">
    <img src="/images/posts/flux-grays.png" alt="Two color swatches, one blue-ish gray, the other orange-ish gray, each with three strips of varying darkness" title="Swatches of varying shades of gray" width="100%">
    <span class="caption">Source: <a href="http://en.wikipedia.org/wiki/File:Grays.svg">http://en.wikipedia.org/wiki/File:Grays.svg</a></span>
</div>


<p>When working in a mixed light source environment, such as an orange incandescent lamp illuminating your living room while you work on your couch with the blue-white glow of your laptop, your brain is actually in a constant tug-of-war.</p>

<p>The brain is trying to create an equilibrium by balancing the colors in the room towards the blue of the laptop, and the laptop light towards the orange of the room. But switching context between looking at your laptop and glancing around the room creates a constant battle for how the brain balances the colors the eye sees. You might better know this tug-of-war as a headache.</p>

<p>F.lux stands to save your headache by correcting this contextual imbalance and tuning your laptop screen to emit light close to that illuminating your working area. Just select from the presets for the different types of lighting: tungsten, halogen, fluorescent, daylight, and a custom setting to set your own color temp.</p>

<p>To demonstrate how beneficial this is, install F.lux and fire up your laptop after the sun has set. Then select "Disable for an hour" from its icon in the menu bar. You will notice how jarring the blueish 6500K screen feels and how it hurts your eyes. It's like hearing a high-pitched screeching noise after listening to the relaxing tunes of, say, <a href="http://www.youtube.com/watch?v=FJbP5wozNUM">Jonn Serrie</a>.</p>

<h3>Color temperature's effect on sleep</h3>

<p>The F.lux website has an entire page <a href="http://justgetflux.com/research.html">dedicated to research</a> that negatively correlates drowsiness, while positively correlating alertness, in people exposed to light that is close in color temperature to that of a normal computer screen. This is essentially sunlight that makes you feel more alert and less tired.</p>

<p>These <a href="http://www.jstage.jst.go.jp/article/jpa/24/2/24_183/_article">findings</a> can be appropriated to say that using your computer or iPad (without F.lux) before attempting to sleep may lead to trouble falling asleep, and/or being less likely to experience the deeper levels of sleep required for to feel fully rested.</p>

<h3>What about the iPad</h3>

<p>The iPad emits a cool light of <a href="http://www.displaymate.com/iPad_2_ShootOut.htm#Measurements">about 7000K</a>, which is even slightly more blue than the normal 6500K daylight and even further from the 2700K incandescent light color temperature.</p>

<p>This leads me to believe that using an iPad in the evening hours would only keep me awake, which isn't a desirable side effect. I'd rather be winding down from the day than trying to keep myself awake. Right now I don't have that problem because I use F.lux on my laptop.</p>

<p>But the F.lux authors do not offer a native iOS app. Instead, they offer an <a href="http://justgetflux.com/ios.html">unofficial iOS app</a> that can only be installed after jailbreaking the device. This is because there are no open APIs to hook into adjusting the colors of the display.</p>

<p>I would love it if Apple incorporated this type of color shifting technology into its hardware by adding a sensor for light temperature and allowing the screen to adjust. It would work as an optional setting, as the color shifting is greatly undesirable when doing work like photo editing, where the screen's color is of utmost importance.</p>

<p>I think the general public would see this as magical, and could even be marketed as a health benefit&mdash;which surely could earn points for Apple in the mass media, who likes to inflate stories about how extended use of technology is bad. Maybe this could even bring the concept of color temperature and its physiological effects more into the mainstream awareness.</p>

<h3>Thoughts?</h3>

<p>It may seem silly that the absence of a single small application would make me think twice about buying a shiny new gadget. But that's really because of the positive impact it has had on me.</p>

<p>It's one of those things that after you start using it, you can't imagine going back.</p>

<p>Have you noticed this jarring effect when using a laptop in the evening?</p>

<p>Or maybe you already use F.lux. Is it as revolutionary for you as it is for me?</p>

<p>Has anyone installed the F.lux iOS app or found an alternative that makes reading from a screen easier at night?</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[git 1.7.8 changes for the everyday developer]]></title>
            <link>http://johnkary.net/blog/git-1-7-8-changes-for-the-everyday-developer/</link>
            <comments>http://johnkary.net/blog/git-1-7-8-changes-for-the-everyday-developer/#disqus_thread</comments>
            <pubDate>Tue, 13 Dec 2011 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[software]]></category><category><![CDATA[git]]></category>
            <guid>http://johnkary.net/blog/git-1-7-8-changes-for-the-everyday-developer</guid>
            <description><![CDATA[git 1.7.8 was released a little over a week ago. Most changes will probably not affect your every day use of git, but a few new features should be useful.]]></description>
            <content:encoded><![CDATA[<p>git 1.7.8 was released a little over a week ago. You can view the 1.7.8 <a href="https://raw.github.com/gitster/git/master/Documentation/RelNotes/1.7.8.txt">release notes</a> for a full list of changes.</p>

<p>Most changes will probably not affect your every day use of git, but a few new features should be useful.</p>

<h3>git merge learned the --edit option to allow editing the merge commit log message</h3>

<p>If your development revolves around feature branches, you probably already branch and merge daily. Depending on your preference, you might preserve merge commits in your log history. If you abide by <a href="http://nvie.com/posts/a-successful-git-branching-model/">gitflow</a> or manually specify the <code>--no-ff</code> option when merging, you are preserving the merge commit.</p>

<p>By default, these commits are auto-generated by git and don't tell you much. They list which files had conflicts, if any, and the name of the merged branch. Unless there is a conflict, you are not given the chance to edit the commit message when making the merge. But thanks to the new <code>--edit</code> option, you can now add a custom message when merging.</p>

<p>Using <code>--edit</code> will cause git to perform the merge then drop you into your <code>core.editor</code> application to edit the merge commit message itself before finally writing it to your history.</p>

<p>You could use this functionality to write a quick all-inclusive summary of a feature you are merging and how it might integrate with other pieces of your software. If I'm working on an internal team project, I'll also include any commands my co-developers need to make in lieu of these new changes.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">git merge --no-ff --edit</span></code></pre></figure></p>

<h3>git grep learned --untracked option</h3>

<p>If you aren't familiar with the Unix tool <a href="http://en.wikipedia.org/wiki/Grep">grep</a>, it basically allows you to search for text within other blocks of text. That block of text may be a large log file or any other type of output sent to your console.</p>

<p><code>git grep</code> is similar to normal grep, but provides grep functionality within the context of a git repository. For example, <code>git grep</code> takes into account the files ignored in <code>.gitignore</code> and will not return results found in those files.</p>

<p>With the new <code>--untracked</code> option, <code>git grep</code> can now search through untracked files as well. So if you have untracked files you might have created but not yet added to your project, you can search through them as well.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">git grep --untracked &quot;string to find&quot;</span></code></pre></figure></p>

<h3>git diff learned --function-context option to show the whole function as context that was affected by a change</h3>

<p>When displaying a diff, a one-line change is normally shown with 3 lines of context. This means the 3 lines both before and after the change are displayed to help remind you where this change was made.</p>

<p><figure class="highlight"><pre><code class="language-diff" data-lang="diff"><span></span> (master) ~/Sites/hallcenter_awards/symfony $ git diff
<span class="gh">diff --git a/apps/applicant/modules/application/actions/actions.class.php b/apps/applicant/modules/application/actions/actions.class.php</span>
<span class="gh">index 5092da4..ec22e6d 100644</span>
<span class="gd">--- a/apps/applicant/modules/application/actions/actions.class.php</span>
<span class="gi">+++ b/apps/applicant/modules/application/actions/actions.class.php</span>
<span class="gu">@@ -21,7 +21,6 @@ class applicationActions extends BaseActions&lt;/p&gt;</span>

&lt;pre&gt;&lt;code&gt;     $this-&amp;gt;route = $this-&amp;gt;getContext()-&amp;gt;getRouting()-&amp;gt;getCurrentRouteName();
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt; $this-&amp;gt;competition = $this-&amp;gt;getCompetitionBySlug($request);
 $this-&amp;gt;forward404Unless($this-&amp;gt;competition-&amp;gt;isPassedOpenDate(), &#39;Competition not open for Applications yet.&#39;);

 $this-&amp;gt;applicant = $this-&amp;gt;getUser()-&amp;gt;getGuardUser();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;</code></pre></figure></p></li>
</ul>


<p>If your change is within a larger function or block of code, like the previous example, 3 lines of context isn't enough to tell exactly where in the function this change was made. git shows us the class declaration as context (seen above as <code>class applicationActions extends BaseActions</code>), but wouldn't it be great if we could see the entirety of the function where the change was made?</p>

<p>The new option <code>--function-context</code> (or its <code>-W</code> short option) attempts to provide you this context, giving you all lines of the function within which your change was made:</p>

<p><figure class="highlight"><pre><code class="language-diff" data-lang="diff"><span></span> (master) ~/Sites/hallcenter_awards/symfony $ git diff --function-context
<span class="gh">diff --git a/apps/applicant/modules/application/actions/actions.class.php b/apps/applicant/modules/application/actions/actions.class.php</span>
<span class="gh">index 5092da4..ec22e6d 100644</span>
<span class="gd">--- a/apps/applicant/modules/application/actions/actions.class.php</span>
<span class="gi">+++ b/apps/applicant/modules/application/actions/actions.class.php</span>
<span class="gu">@@ -11,203 +11,202 @@</span>
 class applicationActions extends BaseActions
 {
     /&lt;em&gt;*
      * Executes before every action
      *
      * Sets navigation breadcrumbs
      &lt;/em&gt;/
     public function preExecute()
     {
         $request = $this-&gt;getRequest();&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;     $this-&amp;gt;route = $this-&amp;gt;getContext()-&amp;gt;getRouting()-&amp;gt;getCurrentRouteName();
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt; $this-&amp;gt;competition = $this-&amp;gt;getCompetitionBySlug($request);
 $this-&amp;gt;forward404Unless($this-&amp;gt;competition-&amp;gt;isPassedOpenDate(), &#39;Competition not open for Applications yet.&#39;);

 $this-&amp;gt;applicant = $this-&amp;gt;getUser()-&amp;gt;getGuardUser();
 $this-&amp;gt;application = $this-&amp;gt;getApplicantCompetitionApplication($this-&amp;gt;applicant, $this-&amp;gt;competition);

 $this-&amp;gt;setSlotBreadcrumbCompetition($this-&amp;gt;competition-&amp;gt;getTitle(), &#39;application_overview&#39;, array(&#39;slug&#39; =&amp;gt; $this-&amp;gt;competition-&amp;gt;getSlug()));
 $this-&amp;gt;setSlotBreadcrumbCompetitionPage(&#39;Application Form&#39;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt; }&lt;/p&gt;

&lt;p&gt; /**&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Displays Application form
*&lt;/li&gt;
&lt;li&gt;If Applicant has already started applying, display their info
*&lt;/li&gt;
&lt;li&gt;@param sfWebRequest $request
*/
public function executeNew(sfWebRequest $request)
{
 $this-&gt;redirectIf($this-&gt;applicationExists($this-&gt;application), array(
     &#39;sf_route&#39; =&gt; &#39;application_edit&#39;,
     &#39;slug&#39; =&gt; $this-&gt;competition-&gt;getSlug(),
 ));
}
// basically continues until the end of the file</code></pre></figure></li>
</ul>
</li>
</ul>


<p>I've found this option rather unreliable, at least within a large PHP class. My tests found <code>--function-context</code> often results in displaying almost all of the original file, and git appears ignorant of PHP's function boundaries. The number of context lines before and after a change seem random, and the diff doesn't necessarily always show all lines of the function, either.</p>

<p>The <a href="http://permalink.gmane.org/gmane.comp.version-control.git/183199">original patch</a> message that introduced this change sheds some light:</p>

<blockquote><p>This implementation has the same shortcoming as the one in grep, namely that there is no way to explicitly find the end of a function. That means that a few lines of extra context are shown, right up to the next recognized function begins.</p></blockquote>

<p>So it appears detecting a function's boundaries is difficult for git. It seems in this instance, git <em>never</em> detects a function boundary and gives us the context of the entire file.</p>

<p>Perhaps support for this functionality will improve in future versions.</p>

<p>For now, <code>git diff</code> already supports the <code>--unified=</code> option, or its short version <code>-U</code>, for displaying a larger number of context lines than the default of 3. At this point, I can only recommend using <code>--unified=</code> to display more lines of context in your diffs.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">git diff --unified=10</span></code></pre></figure></p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[I didn't know it couldn't be done, so I did it]]></title>
            <link>http://johnkary.net/blog/i-didnt-know-it-couldnt-be-done-so-i-did-it/</link>
            <comments>http://johnkary.net/blog/i-didnt-know-it-couldnt-be-done-so-i-did-it/#disqus_thread</comments>
            <pubDate>Mon, 31 Oct 2011 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[book]]></category><category><![CDATA[inspiration]]></category>
            <guid>http://johnkary.net/blog/i-didnt-know-it-couldnt-be-done-so-i-did-it</guid>
            <description><![CDATA[Steve Jobs visited Xerox in 1979 to see the Xerox Star: a computer promoting a revolutionary graphical user interface.<br><br>Jobs loved what he saw. Xerox had developed one of the first GUI’s, one that would ultimately lay the foundation for the concept of “windows” (small W) and the “desktop” we know in modern operating systems.<br><br>When he tasked Bill Atkinson, Atkinson created something even more revolutionary…]]></description>
            <content:encoded><![CDATA[<p>Steve Jobs visited Xerox in 1979 to see the Xerox Star: a computer promoting a revolutionary graphical user interface.</p>

<p>Jobs loved what he saw. Xerox had developed one of the first GUI's, one that would ultimately lay the foundation for the concept of "windows" (small W) and the "desktop" we know in modern operating systems.</p>

<p>Jobs saw the potential of such a user interface, and an ability to capitalize on Xerox's early work, but deliver it at a fraction of the price. He immediately tasked early Apple employee Bill Atkinson with replicating what the two had seen at Xerox.</p>

<p>Atkinson's finished product not only faithfully reproduced what he and Jobs had seen at Xerox, but Atkinson also inadvertently added a revolutionary feature we now take for granted: the ability for windows on screen to <em>overlap</em>.</p>

<p>Biographer Walter Isaacson writes in <a href="http://www.amazon.com/Steve-Jobs-Walter-Isaacson/dp/1451648537">Steve Jobs</a>:</p>

<blockquote><p>"Atkins pushed himself to make this trick work because he thought he had seen this capability during his visit to Xerox PARC."</p></blockquote>

<p>Atkinson told Isaacson:</p>

<blockquote><p>"Because I didn't know it couldn't be done, I was enabled to do it."</p></blockquote>

<p>Sometimes we think we know the rules and limitations of an idea. Until someone comes along and breaks those rules, simply because they didn't know such rules existed.</p>

<p>It's amazing what can be done when nobody tells you you can't.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Getting into The Zone: Music]]></title>
            <link>http://johnkary.net/blog/getting-into-the-zone-music/</link>
            <comments>http://johnkary.net/blog/getting-into-the-zone-music/#disqus_thread</comments>
            <pubDate>Tue, 25 Oct 2011 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[music]]></category>
            <guid>http://johnkary.net/blog/getting-into-the-zone-music</guid>
            <description><![CDATA[I want to talk about how Music affects my ability to be in The Zone: that “deeply creative space where inspiration is built”, as Rands puts it. That mental place where you’re so focused that nothing else matters except the bug you’re hunting, the feature you’re cranking out or the blog post you’re writing.<br><br>By the end of this article I hope you have a better sense of how you choose what to listen to, and that I introduce you to some new artists to increase your productivity when working.]]></description>
            <content:encoded><![CDATA[<p>I want to talk a bit about how Music affects my ability to be in The Zone: that "deeply creative space where inspiration is built", as <a href="http://randsinrepose.com/archives/a-nerd-in-a-cave/">Rands puts it</a>. That mental place where you're so focused that nothing else matters except the bug you're hunting, the feature you're cranking out or the blog post you're writing.</p>

<p>By the end of this article I hope you have a better sense of how <em>you</em> choose what to listen to, and that I introduce you to some new artists to increase your productivity when working.</p>

<p>The most important part for me in finding The Zone is my auditory environment. Where I work varies: the office, at home, 30,000 feet in an airplane, etc. Each environment has its own accompanying distractions: conversations in the next cubicle row, people walking by, my neighbor's rhythmic subwoofer, the barista making a drink order, the impending "Would you like something to drink?" from the flight attendant making her way down the isle.</p>

<p>Music and quality audio equipment have become my great equalizer.</p>

<p>But music alone isn't enough. I can't slip into The Zone just listening to just any music. The type of music that makes me most productive is affected by many factors:</p>

<ul>
<li><strong>What am I working on?</strong> Find a beat and rhythm to match the task. Is it a long, enduring task like fixing an epic bug? Or am I drudging through mindless work and need something to liven it up?</li>
<li><strong>Does the task require internal dialogue, like reading or writing?</strong> Music with lyrics interferes with my thinking. I process things internally by talking to myself in my head. Someone singing in my ear creates another voice commanding my attention, detracting me from clarity.</li>
<li><strong>What's the weather like?</strong> I seem to prefer different types of music given the weather. A sunny Summer day calls for different music than a blustery Winter day.</li>
<li><strong>What time is it?</strong> If I'm winding down for the day I probably don't want to turn on some 140 bpm Trance. That would just keep me awake. Unless that's exactly what I need.</li>
<li><strong>What mood am I in?</strong> Maybe my morning didn't go so well, or maybe I just pushed a great new feature and am reeling with excitement.</li>
</ul>


<p>Whatever the case, what I pick to listen to is both an extension of what mood I'm in and what mental state and mood I <strong>need</strong> to put myself in to be productive in what I'm working on.</p>

<h3>Early Morning (5am - 8am) - Low-key</h3>

<p>I use my mornings to catch up on Twitter, articles I've saved to Instapaper, or sometimes experiment or test out solutions to problems I've been mulling over. Whatever the case, I don't like much distraction.</p>

<p>The darkness and lack of buzz before sunrise allows me to focus. No one is moving except the birds and squirrels outside. Jason Friend and DHH hit it perfectly in their book "Rework":</p>

<blockquote><p>Think about it: When do you get most of your work done? If you're like most people, it's at night or early in the morning. It's no coincidence that these are the times when nobody else is around. [&hellip;] Long stretches of alone time are when you're most productive. When you don't have to mind-shift between various tasks, you get a boatload done.</p></blockquote>

<p>Jazz and low-key minimalism tunes allow me to get my brain moving and cognitively functioning. It's like morning coffee for my ears. Contemplative, but energizing.</p>

<p><strong>Music:</strong><br/>
(<a href="http://store.unseen-music.com/album/eingya">Listen</a>) Goldmund<br/>
(<a href="http://kilimanjaro.bandcamp.com/album/ep-two">Listen</a>) KILIMANJARO<br/>
Gonzales - Solo Piano<br/>
Miles Davis - Kind of Blue</p>

<h3>Morning Work (8am - 12pm)</h3>

<p>By now I'm in the office and ready to start on the day's work. Check email, put out any fires, start structuring my plan for the day.</p>

<p>Right now, I need music to keep me deep in thought and focused. The office usually has many people running around, or having conversations. My goal is to tune them out.</p>

<p>This music is a bit spacey and droning. The minimalism and calming nature also keeps me level-headed about any boogiemen I might discover in my Inbox.</p>

<p>After filing and sending email, it's usually any new support work or maintenance programming on my current project. Tying up loose ends so I can have a productive rest of the day where I'll write new code, perhaps continuing what I was building on earlier in the morning.</p>

<p><strong>Music:</strong><br/>
(<a href="http://www.youtube.com/watch?v=S5Qw9ANrbIg">Listen</a>) Cliff Martinez - Solaris Soundtrack<br/>
(<a href="http://www.youtube.com/watch?v=Nwudva0_ULo">Listen</a>) Jonn Serrie</p>

<h3>Afternoon (1pm - 5pm)</h3>

<p>The post-lunch time slot can be difficult. It's either a continuation of a productive morning, or an uphill battle to stay focused. Depending on the day, over lunch I either played basketball, watched a video/conference talk I saved via Instapaper, read a programming-related book or caught up with co-workers.</p>

<p>I try to pick music to draw me back into my productive morning state, or kick-start me into The Zone if my morning yield was poor. Caffeine with lunch seems to be a reliable way to get me going in the afternoon and keep me focused. Adding the right music to that allows me to get a lot done.</p>

<p>Music during this time varies so much because it depends how my morning went. I usually kick iTunes into Shuffle and play tracks until something hits the spot.</p>

<p>I'm usually in this mode until the end of the work day.</p>

<p><strong>Music:</strong><br/>
Electronic / Trance - <a href="http://www.di.fm/trance/">DI.fm Trance Channel</a> or <a href="http://www.astateoftrance.com/">Armin van Buuren</a><br/>
Radiohead<br/>
Nine Inch Nails<br/>
August Burns Red<br/>
As Tall As Lions<br/>
The Mars Volta<br/>
Circa Survive<br/>
Pendulum</p>

<h3>Night (10pm - 1am) - Drifting</h3>

<p>By now, errands have been run, dinner is finished and cleaned up, I've spent time with friends or my girlfriend, and I'm ready to get back to it.</p>

<p>If I had an early morning or a long day, there's usually another window of quality focus during the nighttime hours. There's not much coming through on Twitter, not many people on chat, and nothing of interest on TV. I can focus again.</p>

<p>This is another period of quality isolation time, allowing me to ignore everything else from the comfort of my couch and crank on more code or work on a blog post. (It's 1:30am as I type this.)</p>

<p>I try not to let myself go to sleep if I'm in the middle of coding a feature or fixing a bug. There's time investment required to orient my mind to what I'm doing, like having a virtual machine running, a few terminal sessions going, a few tabs open in NetBeans and a dirty working tree in git.</p>

<p>But I can usually find this weird blissful mental state where I feel half-asleep but can focus intensely on what I'm doing even though I'm really tired. It's like I can ignore anything else on my mind from the day and just sink into a comfortable place and code. I get lost in the music and time stands still.</p>

<p><strong>Music:</strong><br/>
(<a href="http://www.youtube.com/watch?v=PZwQeZh6rP0">Listen</a>) Godspeed You! Black Emperor<br/>
(<a href="http://bennjordan.bandcamp.com/album/pale-blue-dot">Listen</a>) Benn Jordan - Pale Blue Dot<br/>
(<a href="http://www.youtube.com/watch?v=wZWo8g5sAkY">Listen</a>) Sven Weisemann<br/>
(<a href="http://www.youtube.com/watch?v=Nwudva0_ULo">Listen</a>) Jonn Serrie<br/>
(<a href="http://www.youtube.com/watch?v=lasRLdZYTtk">Listen</a>) Maserati<br/>
(<a href="http://theflashbulb.bandcamp.com/album/soundtrack-to-a-vacant-life">Listen</a>) The Flashbulb<br/>
(<a href="https://myspace.com/themercuryprogram">Listen</a>) The Mercury Program</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[git 1.7.7 changes affecting the everyday developer]]></title>
            <link>http://johnkary.net/blog/git-1-7-7-changes-affecting-the-everyday-developer/</link>
            <comments>http://johnkary.net/blog/git-1-7-7-changes-affecting-the-everyday-developer/#disqus_thread</comments>
            <pubDate>Fri, 14 Oct 2011 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[software]]></category><category><![CDATA[git]]></category>
            <guid>http://johnkary.net/blog/git-1-7-7-changes-affecting-the-everyday-developer</guid>
            <description><![CDATA[git 1.7.7 was released within the last few weeks. You can view the 1.7.7 release notes for a full list of changes.<br><br>Most changes will probably not affect your every day use of git, but two new additions should prove very useful for many developers.]]></description>
            <content:encoded><![CDATA[<p><a href="http://git-scm.com/">git 1.7.7 was released</a> within the last few weeks. You can <a href="https://raw.github.com/gitster/git/master/Documentation/RelNotes/1.7.7.txt">view the 1.7.7 release notes</a> for a full list of changes.</p>

<p>Most changes will probably not affect your every day use of git, but two new additions should prove very useful for many developers:</p>

<h3>"git stash" learned an "--include-untracked option"</h3>

<p><a href="http://schacon.github.io/git/user-manual.html#interrupted-work">git stash</a> is one of my favorite git features. If you don't know about <code>git stash</code> yet, it allows you to take all of the changes in your working tree that haven't been committed and temporarily store them, then cleans your working tree.</p>

<p>Basically it tells git, "Hey, I'm not ready to commit all of these changes, but I really need to get back to the way my repository was right after I made my last commit. So save my most recent changes with this given description, so I don't forget what I was working on, and I'll come back to them later."</p>

<p>Prior to git 1.7.7, if you ran <code>git stash save</code> it would only stash changes for files that were already under version control. So if you had created a new file that was part of the feature you were working on and wanted to stash it, you were stuck with an ugly work around of having to add it to the repo using <code>git add</code>, then stashing your changes. When later replaying the stash, those files would still appear in the staging area/index.</p>

<p>But with the new option <code>--include-untracked</code>, or simply <code>-u</code>, <code>git stash</code> can now save your working tree exactly the way you had it when you created the stash.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">git stash -u</span>
<span class="go">git stash --include-untracked</span></code></pre></figure></p>

<h3>"git submodule update" reports any errors at the end instead of halting on error</h3>

<p><a href="http://schacon.github.io/git/user-manual.html#submodules">git submodules</a> allow you to embed and track a foreign repository in your parent repository. They are great when you want to distribute code between multiple projects, but keep the distributed code in its own repository with its own version history.</p>

<p>Prior to git 1.7.7, if you ran <code>git submodule update</code> and there was a problem, git would immediately halt. Halting in the middle of updating might update some of your submodules and leave others unupdated.</p>

<p>But now, git will continue updating all submodules and instead report a list of errors after attempting to update all submodules.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Thoughts on Carl Sagan's "Pale Blue Dot"]]></title>
            <link>http://johnkary.net/blog/thoughts-on-carl-sagans-pale-blue-dot/</link>
            <comments>http://johnkary.net/blog/thoughts-on-carl-sagans-pale-blue-dot/#disqus_thread</comments>
            <pubDate>Fri, 07 Jan 2011 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[books]]></category><category><![CDATA[carl-sagan]]></category>
            <guid>http://johnkary.net/blog/thoughts-on-carl-sagans-pale-blue-dot</guid>
            <description><![CDATA[Carl Sagan’s book “Pale Blue Dot” is a truly inspirational book. It has given me a new outlook on the fragility of life on Earth, and cultured new thoughts on what interplanetary travel might mean for the future of the human species.<br><br>Here, I detail some of my thoughts on the ideas expressed in the book.]]></description>
            <content:encoded><![CDATA[<p>Carl Sagan's book "<a href="http://www.amazon.com/Pale-Blue-Dot-Vision-Future/dp/0345376595/">Pale Blue Dot</a>" is a truly inspirational book. It has given me a new outlook on the fragility of life on Earth, and cultured new thoughts on what interplanetary travel might mean for the future of the human species.</p>

<div class="image">
    <a href="/images/posts/pale_blue_dot.jpg"><img src="/images/posts/pale_blue_dot.jpg" title="Pale Blue Dot" width="420"></a>
</div>


<p>Sagan lays out two over-arching requirements that must be met for the survival of the human species, which he reinforces in various ways throughout the book:</p>

<h3>We must venture outside Earth, and ultimately outside the dependency of the Sun, if humans are to survive the end of the Earth</h3>

<p>The Sun and Earth have limited lifespans, albeit billions of years. The Sun will eventually turn into a red giant star (the current estimate being in about 5 billion years.) Increasing in size and amount of light energy emitted during this process, it will alter the atmospheric composition of Earth by increasing its surface temperature.</p>

<p>These atmospheric changes will cause a chain reaction in all living organisms on Earth as the atmosphere and oceans begin to boil away. The balance of life that has evolved while the Earth is in its current stage will cease to exist, perhaps giving way to a new quality of life and organisms better suited to tolerate the new conditions, before all atmosphere, water and upper layers of earth are burned away.</p>

<p>Finally, after all molten matter is stripped from the surface, Earth's iron core will be engulfed by the expanding horizon of the red giant star previously known as our Sun. All human creations, trees, grass, dirt, fossil fuels, buildings, gravestones, and all remains of every organism to ever grace the Earth&hellip; all planetary matter will have been broken down into other energy, and ultimately re-distributed into surrounding space, to one day be recombined into (anti?) matter or energy somewhere else in the Universe.</p>

<p>Our history as a species and everything every single human has ever worked for will be gone. The only remaining remnants of our existence will be the light and radio waves that were reflected and emitted during our existence on Earth. Anyone observing Earth from billions of light-years away would actually be observing Earth as we currently inhabit it. Wave to them.</p>

<p>That is unless we destroy ourselves first.</p>

<h3>We mustn't destroy ourselves</h3>

<p>Whether through rash decision by an ideologic or radical peoples, or by means of ignorance or plain selfishness, the human species has the ability to destroy itself. Whether through technological means such as nuclear war, or selfishness and shortsightedness in damaging the delicate life balance under which current organisms have evolved.</p>

<p>The human species, in its development of technology and its ever-increasing rate of advancement, has harnessed power capable of mass destruction. While this power might seem small in scope of the energy harnessed by the perpetual motion of the Universe, it is enough to destroy our entire world. Whether used recklessly by way of a political statement, or pure accident, the technology enabling this power is now a lit fuse that could easily disrupt our existence.</p>

<p>By establishing a human presence on surrounding worlds and stars, we can lower our vulnerability to catastrophe like this and the fragility of the Earth that ultimately cultivated us.</p>

<p>Sagan argues through much of the book that the first step in exploring the stars is sending humans to Mars. But his pessimistic outlook on the state of the human race suggests he believes humans will destroy themselves and their planet before spacefaring nations can foster the finances to accomplish such a feat.</p>

<p>Given the current financial state of the United States in 2011, it would seem increasingly unlikely for such an undertaking to see approval by its governing bodies anytime soon.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[JavaScript Effects: Knowing "when" is more important than "how"]]></title>
            <link>http://johnkary.net/blog/javascript-effects-knowing-when-is-more-important-than-how/</link>
            <comments>http://johnkary.net/blog/javascript-effects-knowing-when-is-more-important-than-how/#disqus_thread</comments>
            <pubDate>Thu, 18 Nov 2010 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[best-practices]]></category><category><![CDATA[usability]]></category>
            <guid>http://johnkary.net/blog/javascript-effects-knowing-when-is-more-important-than-how</guid>
            <description><![CDATA[You have undoubtedly seen many tutorial sites showing off how to implement the newest whiz-bang features of modern JavaScript libraries. While most of these sites do an adequate job of showing users “how to” implement features, they almost always neglect teaching when to use these techniques, and more importantly, when to forgo them.]]></description>
            <content:encoded><![CDATA[<p>You have undoubtedly seen many tutorial sites showing off how to implement the newest whiz-bang features of modern JavaScript libraries. While most of these sites do an adequate job of showing users "how to" implement features, they almost always neglect teaching <em>when</em> to use these techniques, and more importantly, when to forego them.</p>

<p>At <a href="http://www.ku.edu">the University of Kansas</a> where I currently do web development work at the time of this writing, we recently had a random student developer from another large University call our help desk and suggest we implement a collapsable content list (an <a href="http://api.jqueryui.com/accordion/">accordion</a>) on our <a href="http://www.ku.edu/academics/schools/">Academic Schools &amp; Departments page</a> (seen below.)</p>

<div class="image">
    <img src="/images/posts/ku-academics.png" title="KU: Academic Schools &amp; Departments" width="500">
</div>


<p>Even though the content is in a list format with headings over each area, I chose not to use an accordion. <strong>Why not?</strong> Let's consider a few things.</p>

<h3>How did the user arrive at this page?</h3>

<p>Looking at our Google Analytics numbers, about 99% of visits to the Academics page come from the KU's homepage and primary site pages. A link to "Academics" lives in the top-navigation, so it's very visible. This indicates the user is already browsing around our primary site, where they find general info about the University.</p>

<p>This particular page is also the 3rd-most visited page on KU's main website, only behind the Homepage and A-Z's "E" page (where users go to click on "Email.") So it's seeing a lot of traffic.</p>

<h3>How many clicks deep is this page? What other pages might the user have encountered before arriving at this page?</h3>

<p>This page is one click deep at all times. A user can access this page with one click from almost any other page on KU's website, so its content should be geared to hit a wide audience with a variety of expectations.</p>

<h3>What is the context of this page?</h3>

<p>In this case, the Search tab is active when the user first arrives. Users are accustomed to (and often prefer) searching to find the content they want, so we let them Search first. Search provides instant gratification and is a low time investment opposed to reading a long page of text or links.</p>

<div class="image">
    <img src="/images/posts/ku-academics-search.png" title="KU: Academics Search" width="500">
</div>


<p>We also operate under the assumption that after a user finds the information they seek, they stop looking. If search meets their needs, they will not likely encounter our list of Schools &amp; Departments.</p>

<p>So what can we conclude about the context of this page and the user arriving there?</p>

<ul>
<li>The user is looking for info about the schools and departments KU offers.</li>
<li>Since the user was first provided a Search box, they likely already searched for the info they wanted and their needs were not met.</li>
<li>They may or may not know the name of the department they're looking for and&hellip;

<ul>
<li>want to see a hierarchy of schools and departments</li>
<li>want to see all options and pick the one that best matches what they're looking for</li>
</ul>
</li>
</ul>


<p>Now that we've asked given context to the page visitors, let's pick up where most tutorials start: the content being presented.</p>

<h3>What type of content is this?</h3>

<p>Our very long list is broken down in a hierarchy by School, then Department. If we took into account only the hierarchy and length, a collapsed list would absolutely solve that problem. But let's go beyond content tutorials and dig a bit deeper.</p>

<h3>Does the user need to see all content at once?</h3>

<p>In this case, yes, they likely do. The user didn't find what they wanted using the search, and they want to see all possible options to find the one that best matches what they're looking for.</p>

<p>Remember, this user might not know what they're looking for because this page is not very deep in the navigation structure. So rather than hide a bunch of content from the user, we give it to them all at once. They can use CTRL + F to search the page content for a specific department, or quickly skim over each school and through the department lists.</p>

<h3>Conclusion</h3>

<p>These are all questions you should ask yourself before implementing any type of visual effect or design element. You might think you're being clever, but you could just as easily be hurting the usability of your site's content.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Who Cares? Crowdsourcing Your News Intake]]></title>
            <link>http://johnkary.net/blog/who-cares-crowdsourcing-your-news-intake/</link>
            <comments>http://johnkary.net/blog/who-cares-crowdsourcing-your-news-intake/#disqus_thread</comments>
            <pubDate>Fri, 10 Sep 2010 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[media]]></category><category><![CDATA[rant]]></category>
            <guid>http://johnkary.net/blog/who-cares-crowdsourcing-your-news-intake</guid>
            <description><![CDATA[Looking at some generic news aggregate site, it seems there’s a lot of important things going on in the news. Some radical pastor wants to burn Korans. Huge fires are engulfing a San Francisco neighborhood. “Evil” zombies are now back. In 3D.<br><br>Does any of that really affect you? No, really… does it?<br><br>NO! And if you think it does, it doesn’t. Want proof?]]></description>
            <content:encoded><![CDATA[<p>Looking at some generic news aggregate site, it seems there's a lot of important things going on in the news. Some radical pastor wants to burn Korans. Huge fires are engulfing a San Francisco neighborhood. "Evil" zombies are now back. In 3D.</p>

<p>Does any of that really affect you? No, really&hellip; does it?</p>

<p>NO! And if you think it does, it doesn't. Want proof?</p>

<p>Before reading any news article today, insert "Who cares if&hellip;" in front of the headline.</p>

<p>Who cares if some radical pastor wants to burn Korans?<br/>
Who cares if huge fires are engulfing a San Francisco neighborhood? (OK, unless you have family in the neighborhood.)
Who cares if there's another meaningless evil zombie movie, now in 3D?</p>

<p>Who cares? Not me, and not you.</p>

<p>We're fed this junk news because the news companies NEED something to cover. If they don't cover SOMETHING they're sending out dead air, or blank newspapers, or a news junkie's cryptonite: re-runs.</p>

<p>It's not just national and local news networks and newspapers. It's all over our digital life too.</p>

<p>Look at your RSS Feed (if you even still use one.) Your Twitter feed. Your Facebook feed. How many of those stories do you actually read? How many do you actually care about? You probably don't even have enough time to keep up with it all.</p>

<p>People follow this junk news so they can keep up on current events, or have something to talk about at the water cooler, or chat up acquaintances at awkward dinners and family get togethers. People get a sense of pride from knowing "what's going on in the world!"</p>

<p>Some people get satisfaction relaying the newest news message to someone else. Or being the first to know something among their friends. It actually validates their news obsession and gives them a sense of being "in the know."</p>

<p>We're so bent on crowdsourcing things these days&hellip; how about crowdsource your news reading?</p>

<p>Let everyone else keep up on news for you. Let them tell you about it over lunch or a drink. This will not only free you up for more important things, but reaffirm your friend's need to feel important for catching you up on the big story.</p>

<p>So purge your RSS feed. Stop following Tech Crunch, Gizmodo, Engadget and Apple News. 95% of their stories don't matter anyway.</p>

<p>Unfollow all but a subset of your Twitter crew. Focus on the ones putting out meaningful content and not just noise.</p>

<p>Unfriend all those acquaintances and old high school friends on Facebook. Or stop logging in so often, or close your account all together. Take a friend out to lunch if you want to catch up on what they've been doing instead of passively taking in their life.</p>

<p>If something big is happening, let someone else tell you about it. Then ask yourself, who cares? It won't be you.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[MediaTemple "WordPress Redirect Exploit" exposes weakness in GridServer security]]></title>
            <link>http://johnkary.net/blog/mediatemple-wordpress-redirect-exploit-exposes-weakness-in-gridserver-security/</link>
            <comments>http://johnkary.net/blog/mediatemple-wordpress-redirect-exploit-exposes-weakness-in-gridserver-security/#disqus_thread</comments>
            <pubDate>Wed, 21 Jul 2010 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[security]]></category><category><![CDATA[wordpress]]></category>
            <guid>http://johnkary.net/blog/mediatemple-wordpress-redirect-exploit-exposes-weakness-in-gridserver-security</guid>
            <description><![CDATA[Instances of WordPress installed on certain clusters of MediaTemple’s GridServer were recently hit with an exploit that appended an external JavaScript to each post’s content field, ultimately redirecting to redirecting to a TinyURL address, resolving to the domain qooglesearch.com.<br><br>MediaTemple asserts in a July 16, 2010 blog entry, “We do not believe that this is an infrastructure issue, but we are still investigating the root cause(s).”<br><br>I believe I have evidence to the contrary.]]></description>
            <content:encoded><![CDATA[<p>Instances of WordPress installed on certain clusters of MediaTemple's GridServer [also called (gs)] were recently hit with an <a href="http://wiki.mediatemple.net/w/WordPress_Redirect_Exploit">exploit</a> that appended an external JavaScript to each post's content field, ultimately redirecting to redirecting to a TinyURL address, resolving to the domain http://www.qooglesearch.com.</p>

<p>MediaTemple asserts in a <a href="http://weblog.mediatemple.net/weblog/2010/07/16/1404-wordpress-redirect-exploit-2/">July 16, 2010 blog entry</a>, which as of November 2012 had been removed from their site: "We do not believe that this is an infrastructure issue, but we are still investigating the root cause(s)."</p>

<p>I believe I have evidence to the contrary.</p>

<hr />

<p>I noticed today my WordPress blogs had been hit by the Redirect Exploit. I followed the <a href="http://wiki.mediatemple.net/w/WordPress_Redirect_Exploit#Clean-Up">fix instructions</a> and came across something fishy.</p>

<p>Before upgrading one of my old blogs from WordPress 2.5 to 2.6, I had made a full copy of the database. So I then had two identical databases up with different names. I switched the database name in my WordPress config and went along with the upgrade. So my WordPress 2.5 database lay dorment, without an active frontend to administer it.</p>

<p>I ran the fix code against my old WP 2.5 database, and found it had been injected with the exploit code, <strong>even without an active WordPress install pointing to it.</strong></p>

<p>This is significant because most WordPress exploits are local to the installation itself, and likely do not affect installations on a host's entire network.</p>

<p><strong>This leads me to believe the exploit was carried out as a result of a system-level security breach by obtaining a list of all databases on all compromised accounts, and running an UPDATE query to inject code into every WordPress database.</strong></p>

<hr />

<p>MediaTemple's head of support and a few sysadmin/security guys were nice enough to give me a call after I put out <a href="https://twitter.com/johnkary/status/19107499517">this tweet</a> to discuss what I had found, and divulge a bit of what they know.</p>

<p>They believe someone possibly obtained a list of database credentials, then used those credentials to scan and inject code. They said they had already enacted some system changes to mitigate some security issues, and were in the process of re-architecting some aspects of the shared system.</p>

<p>I expect we will see more news from the MediaTemple crew about this exploit in the coming weeks.</p>

<p>To prevent further exploits, you should manually change the password of every database account on your (gs) account, and check that your /domains/ directory is not world-readable (chmod <del>755</del> 750)</p>

<p><strong>July 21, 7:50pm Update:</strong> A previous version of this article had info that could be interpreted as users having access to other users accounts on the system. That was not the intended message and the wording has been updated to reflect this change.</p>

<p><strong>September 30, 2010 Update:</strong> Since this article, I have needed to remove malicious JavaScript from this blog two more times, each time with a slightly different-looking exploit code. The most recent exploit I discovered yesterday when a user reported Google was reporting my blog as hosting malware. Sadly, this was not limited to just my blog.</p>

<p>MANY domains on my MediaTemple grid-server account were found to be listed as hosting malware by Google. <strong>Even domains without WordPress installed.</strong> This points to a larger issue where either the server itself is insecure or a web application on the server (WordPress?) is being used as an attack vector to modify files on the filesystem.</p>

<p><strong>2011 Update:</strong> I have since left MediaTemple's (gs) hosting and started hosting on a dedicated VPS. Surprise, none of my sites, this blog included, have not been knowingly exploited since.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[I May Be Doing it Wrong, But I Have My Sanity]]></title>
            <link>http://johnkary.net/blog/i-may-be-doing-it-wrong-but-i-have-my-sanity/</link>
            <comments>http://johnkary.net/blog/i-may-be-doing-it-wrong-but-i-have-my-sanity/#disqus_thread</comments>
            <pubDate>Tue, 16 Mar 2010 00:00:00 -0500</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[php]]></category><category><![CDATA[rant]]></category><category><![CDATA[best-practices]]></category>
            <guid>http://johnkary.net/blog/i-may-be-doing-it-wrong-but-i-have-my-sanity</guid>
            <description><![CDATA[Marco Tabini recently wrote on the php|architect blog that “programmers are doing it wrong.” He argues that many programmers have become hung up on writing mythical perfect code that abides by all modern best practices instead of doing what we are hired to do: solve problems quickly and efficiently. But if you spend time writing it well the first time, you too can save your sanity.]]></description>
            <content:encoded><![CDATA[<p>Marco Tabini <a href="http://www.phparch.com/2010/03/programming-youre-doing-it-wrong/">recently wrote</a> on the php|architect blog that "programmers are doing it wrong." He argues that many programmers have become hung up on writing mythical perfect code that abides by all modern best practices instead of doing what we are hired to do: solve problems quickly and efficiently. But if you spend time writing it well the first time, you too can save your sanity.</p>

<p>I'll admit, I'm in that latter group of striving to write "perfect code." I constantly read articles, pour over well-written open-source code (mostly Symfony code) and review conference presentation slides posted by notable developers on <a href="http://www.slideshare.net/search/slideshow?searchfrom=header&amp;q=PHP">SlideShare</a>.</p>

<p>Like every one of us, I've come a long way from where I was when I started writing PHP. (With a long way to go, still, I'm sure.) I remember the days of constantly hitting syntax errors before discovering IDEs and performing search and replace over an entire project to update code duplicated across multiple files. Yeah, it was a nightmare. One I would prefer to not repeat.</p>

<p>So while I'm not going to read a single article about a design pattern and roll it into my next production product, I am going to continue learning from the best developers in the industry and explore the concepts they advocate.</p>

<h3>The Redheaded Stepchild: WordPress (and its many siblings)</h3>

<p>Marco also claims that even though WordPress is regarded as "unmaintainable" by many in the community, it has plenty of maintainers and many plugin contributors. But making the "quantity over quality" argument here holds no weight.</p>

<p>WordPress has a lot of maintainers because it still relies on concepts and methods that many junior developers think are OK. Meaning, "WordPress developers" haven't become fed up with their code quality enough to push deeper. WordPress' codebase is how beginners write code, so it is familiar to a large number of developers eager to put their mark on something. Many PHP programmers never progress past this stage. And their ignorance is probably bliss.</p>

<p>Given WordPress' popularity, many junior developers view the code under the hood and think, "WordPress is successful. This must be how you write successful PHP code." NO! It's not! Writing code like that is what makes you hate your job!</p>

<p>Marco argues that if your code works and you are releasing software, you are doing it right. But how much did you hate your life when&hellip;</p>

<ol>
<li>you had to fix more than one security issue per release cycle</li>
<li>you spent hours trying to fix a single bug, only to have squash it, and it broke twenty other things</li>
<li>realizing you missed other occurrences of that same bug after fixing it in the previous release</li>
<li>the API/software you write third-party code for breaks your plugin with every release (just like WordPress does.)</li>
</ol>


<p>Having to fix broken code not done well the first time will cost your client more money, and cost you your patience and ambition. Spend time thinking about your next function before you haphazardly write it. Think about its context, where might it be reused in the future, and what parts could be swapped out to make it more reusable and easier to test.</p>

<p>Where do you want to spend your time&hellip; Up front researching, reading and writing quality code up front with <a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">DRY principles</a> and hopefully at least <a href="https://leanpub.com/grumpy-testing">some unit tests</a>? Or at crunch time cursing your monitor and slamming your head on your desk agonizing over code you wrote 3 months ago?</p>

<h3>Do Something! Learn From the Best</h3>

<p>When you're writing code or debugging old code and thinking, "There's got to be a better way&hellip;!" There is.</p>

<p>Start with the PHP Advent series: <a href="http://phpadvent.org/2009">2009</a>, <a href="http://phpadvent.org/2008">2008</a>, <a href="http://shiflett.org/blog/2007/dec/php-advent-calendar-2007">2007</a>.</p>

<p>Learn <a href="http://fabien.potencier.org/article/11/what-is-dependency-injection">what Dependency Injection is</a> and <a href="http://www.slideshare.net/fabpot/dependency-injection-confoo-2010">how you can use it</a>.</p>

<p><a href="https://twitter.com/pmjones">Follow</a> <a href="https://twitter.com/shiflett">some</a> <a href="https://twitter.com/coates">of</a> <a href="https://twitter.com/derickr">the</a> <a href="https://twitter.com/s_bergmann">most</a> <a href="https://twitter.com/rasmus">respected</a> <a href="https://twitter.com/giorgiosironi">PHP</a> <a href="https://twitter.com/jwage">developers</a> <a href="https://twitter.com/phparch">on</a> <a href="https://twitter.com/fabpot">Twitter</a>.</p>

<p>And start writing better code.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Nominating Lawrence, Kansas for Google's fiber network experiment]]></title>
            <link>http://johnkary.net/blog/nominating-lawrence-kansas-for-googles-fiber-network-experiment/</link>
            <comments>http://johnkary.net/blog/nominating-lawrence-kansas-for-googles-fiber-network-experiment/#disqus_thread</comments>
            <pubDate>Thu, 11 Feb 2010 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[rant]]></category>
            <guid>http://johnkary.net/blog/nominating-lawrence-kansas-for-googles-fiber-network-experiment</guid>
            <description><![CDATA[Google announced yesterday on their blog that they are venturing into installing fiber-to-the-curb for residential users, essentially as an alternative ISP. Their goals include not only delivering faster Internet to more people, but also giving developers and users a wealth of bandwidth at their disposal and see what they can do with it.<br><br>Google asked for nominations of cities that might be a good fit for the project, so I wrote a recommendation letter for where I live in Lawrence, Kansas.]]></description>
            <content:encoded><![CDATA[<p>Google announced yesterday <a href="http://googleblog.blogspot.com/2010/02/think-big-with-gig-our-experimental.html">on their blog</a> that they are venturing into installing fiber-to-the-curb for residential users, essentially as an alternative ISP. Their goals include not only delivering faster Internet to more people, but also giving developers and users a wealth of bandwidth at their disposal and see what they can do with it.</p>

<p>Google asked for <a href="http://www.google.com/appserve/fiberrfi/public/options">nominations of cities</a> that might be a good fit for the project, so I wrote a recommendation letter for where I live in <a href="http://maps.google.com/places/us/kansas/lawrence?gl=us">Lawrence, Kansas</a>:</p>

<hr />

<h3>Dear Google,</h3>

<p>Lawrence, Kansas is a quintessential college town and home to the University of Kansas, with total population of about 90,000 most of the year, and about 70,000 when the University is not in session. Lawrence is relatively small geographically, covering only about 28 square miles, and is home to a talented technology and development community. Now the interesting parts.</p>

<p>Lawrence's local cable provider, Sunflower Broadband, holds a bit of a monopoly on cable service in the area, leaving many residents wishing for more options for Internet access other than Sunflower or AT&amp;T DSL/U-verse. Sunflower is also one of the few cable companies in the nation that use bandwidth transfer limits on most of their tiered accounts.</p>

<p>I subscribe to the middle tier account at 7Mbps. Within the last few months, Sunflower upped the bandwidth cap from 15GB to just 25GB. While additional bandwidth is available for purchase, if you transfer over your limit, you are charged per-GB. Google's presumably unmetered-bandwidth fiber network would give residents yet another legitimate high-speed internet option and provide Lawrence's talented development community bandwidth to play with.</p>

<p>The University of Kansas in Lawrence is also already <a href="http://www.oread.ku.edu/2007/october/22/fiber.shtml">connected to fiber optic lines</a> that run along Interstate 70, through Kansas City out to Manhattan, KS. While I don't know the politics involved, Google could leverage existing infrastructure and run their own lines parallel to existing lines, making the process of installing new lines more cost efficient.</p>

<p>Being home to a leading research institution in the University of Kansas, Lawrence is also home to many well-connected technology advocates and Internet technology pioneers. The Lawrence development community is very active and produces original high-quality software used by people across the world. A successful launch in Lawrence would generate a large buzz in the technology and social media niche, generating word-of-mouth feedback.</p>

<p>The US Department of Energy recently provided a grant to local power company, Westar Energy, providing the electric company funds to <a href="http://www2.ljworld.com/news/2009/nov/01/lawrence-homes-test-smart-meters/">install "smart energy grid" meters</a> in the majority of Lawrence homes. These new meters will allow customers to monitor their energy usage online. If Google were to lay fiber-to-the-curb for home use, they could possibly negotiate a business opportunity with Westar Energy as the data-communications partner for this grant project, perhaps elevating some of the implementation costs.</p>

<p>As outlined above, Lawrence is small enough, yet large enough to sustain such a project. Fiber-to-the-curb would be a welcomed option for another Internet provider to alleviate bandwidth caps, and would likely be used by many in the Lawrence tech community to build next-generation hardware and software. Existing infrastructure would lower the barrier for implementation, while strong influence in the national technology community would bring much feedback from Lawrence's progressive technology community.</p>

<p>Thank you for reading,<br/>
John Kary<br/>
Lawrence, Kansas resident</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Ditch Outlook/Entourage for managing your Exchange calendar using DavMail and iCal]]></title>
            <link>http://johnkary.net/blog/ditch-outlook-entourage-for-managing-your-exchange-calendar-using-davmail-and-ical/</link>
            <comments>http://johnkary.net/blog/ditch-outlook-entourage-for-managing-your-exchange-calendar-using-davmail-and-ical/#disqus_thread</comments>
            <pubDate>Sat, 06 Feb 2010 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[software]]></category>
            <guid>http://johnkary.net/blog/ditch-outlook-entourage-for-managing-your-exchange-calendar-using-davmail-and-ical</guid>
            <description><![CDATA[Using a little app called DavMail, you use any CalDEV-enabled calendar app to manager your Exchange calendar, including Apple’s iCal. From their site, “DavMail is a POP/IMAP/SMTP/Caldav/LDAP exchange gateway allowing users to use any mail/calendar client (e.g. Thunderbird with Lightning or Apple iCal) with an Exchange server, even from the internet or behind a firewall through Outlook Web Access.” So assuming your company has OWA setup, keep reading.]]></description>
            <content:encoded><![CDATA[<p>When Apple announced "full Exchange integration" in Snow Leopard, everyone thought they could finally swoosh the Entourage icon from their dock. But when it was known only Exchange 2007+ was supported, the rest of the corporate world sighed and continued limping along on their older-than-Exchange 2007 servers.</p>

<p>But using a little app called <a href="http://davmail.sourceforge.net/">DavMail</a>, you use any CalDEV-enabled calendar app to manager your Exchange calendar, including Apple's iCal. From their site:</p>

<blockquote><p>DavMail is a POP/IMAP/SMTP/Caldav/LDAP exchange gateway allowing users to use any mail/calendar client (e.g. Thunderbird with Lightning or Apple iCal) with an Exchange server, even from the internet or behind a firewall through Outlook Web Accessl.</p></blockquote>

<p>So assuming your company has OWA setup, keep reading.</p>

<p>Running DavMail, you will be able to interface from your local machine to the remote Exchange server with full Calendar integration, full attendee completion and full free/busy support all via iCal and Mail.app. Let's get started.</p>

<h3>NOTE Before We Begin&hellip;</h3>

<blockquote><p>At time of publication, DavMail is currently at stable version <strong>3.6.3</strong>. A very recent bug fix allows DavMail to work with OWA login screens with some customizations (like we use at the University of Kansas) so I will go through how to <a href="http://davmail.sourceforge.net/build.html">build DavMail from source</a>. I assume when <strong>3.6.4</strong> is available, this will not be necessary.</p></blockquote>

<h3>Step 0 - Build from source</h3>

<p>Use Subversion to export the latest build from the DavMail repository:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">svn export http://davmail.svn.sourceforge.net/svnroot/davmail/trunk davmail</span></code></pre></figure></p>

<p>Change into the new <code>davmail</code> directory and use <a href="http://ant.apache.org/">Apache Ant</a>, which comes standard in Snow Leopard, to build the installers:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">cd davmail</span>
<span class="go">ant</span></code></pre></figure></p>

<p>You will end up with binaries or installers for all supported operating systems, but we're only interested in DavMail.app for Mac. Let's copy it to our Applications directory then launch it.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">cp -r dist/DavMail.app /Applications</span>
<span class="go">open /Applications/DavMail.app</span></code></pre></figure></p>

<h3>Step 1 - Setting up DavMail</h3>

<p>Open the Preferences menu from the DavMail application drop-down menu. This is where you enter your OWA URL and set the local ports the DavMail daemon will listen on.</p>

<div class="image">
    <img src="/images/posts/DavMail-Gateway-Settings.jpg" title="DavMail Gateway Settings" width="500">
</div>


<p>The normal format of the OWA URL is <code>https://exchangeServer/owa/</code> for Exchange 2007, or <code>https://exchangeServer/exchange/</code> for older versions. Take note of the Caldev and LDAP ports, as we're going to use them to setup iCal. Obviously you want to use HTTPS here to encrypt communication between your machine and the OWA server.</p>

<h3>Step 2 - Connect iCal to your Exchange Calendar</h3>

<p>Launch iCal and open its Preferences window. Under the Accounts tab, click the <code>+</code> button to add a new calendar account.</p>

<p>Enter the following options:</p>

<p>Account type: <strong>CalDAV</strong><br/>
User name: <strong>Your username WITHOUT the @domain.com</strong><br/>
Password:<strong>Your password</strong><br/>
Server address: <strong>http://localhost:1080/principals/users/username@domain.com</strong>
(where <code>1080</code> is your CalDAV port, and <code>username@domain.com</code> is your full username)</p>

<p>Click Create.</p>

<div class="image">
    <img src="/images/posts/DavMail-iCal.jpg" title="iCal" width="500">
</div>


<p>iCal will ask if you want to send your login credentials over an unsecured connection because we entered <strong>http</strong>://localhost&hellip; as our CalDEV server address instead of an HTTPS connection. But because we entered our OWA address as HTTPS, we are transmitting our credentials securely. For more info on security and DavMail, look under "Security" in the <a href="http://davmail.sourceforge.net/faq.html">DavMail FAQ</a>.</p>

<h3>Step 3 - Setup attendee looking in LDAP</h3>

<p>DavMail has pretty detailed instructions for doing this on its website, so rather than repeat them here, read the official documentation page for setting up <a href="http://davmail.sourceforge.net/osxdirectorysetup.html">attendee completion using LDAP</a>.</p>

<h3>Step 4 - And you're done!</h3>

<p>You should now have a new Calendar in iCal and be able to create new calendar events and designate attendees right from iCal.</p>

<hr />

<h3>Step 5 - Bonus: Hide DavMail dock icon</h3>

<p>You don't really need to interact with DavMail from the dock since it's more of an agent-application. We can hide the DavMail dock icon by editing the <code>Info.plist</code> and adding the <code>LSUIElement</code> key.</p>

<p>From Terminal, open DavMail.app's <code>Info.plist</code> using your favorite editor. In my case, I'll edit the text file using vi:</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">vi /Applications/DavMail.app/Contents/Info.plist</span></code></pre></figure></p>

<p>We now need to add the <a href="http://developer.apple.com/mac/library/documentation/General/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/20001431-108256">LSUIElement key</a> and set it to <code>true</code>. Find the area of code around something like <code>&lt;CFBundleIconFile&gt;&lt;/key&gt;&lt;string&gt;tray.icns&lt;/string&gt;</code> and add this new key definition after it:</p>

<p><figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span></span><span class="nt">&lt;key&gt;</span>LSUIElement<span class="nt">&lt;/key&gt;</span>
<span class="ni">&amp;lt;</span>true&gt;</code></pre></figure></p>

<p>Save the <code>Info.plist</code> file and relaunch DavMail. The dock icon will be hidden but will still appear in the menu bar.</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Keeping your users' trust in web applications]]></title>
            <link>http://johnkary.net/blog/keeping-your-users-trust-in-web-applications/</link>
            <comments>http://johnkary.net/blog/keeping-your-users-trust-in-web-applications/#disqus_thread</comments>
            <pubDate>Tue, 08 Dec 2009 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[rant]]></category><category><![CDATA[usability]]></category>
            <guid>http://johnkary.net/blog/keeping-your-users-trust-in-web-applications</guid>
            <description><![CDATA[Trust is priceless. Breaking the trust bond in a relationship, whether friendly, emotional or vendor-to-end-user, is a serious breach of social contract. As web app developers and content creators, we must instill trust in our users with the goal of making them feel comfortable using our applications and ultimately giving up some of their personal info.]]></description>
            <content:encoded><![CDATA[<p>Trust is priceless. Breaking the trust bond in a relationship, whether friendly, emotional or vendor-to-end-user, is a serious breach of social contract. As web app developers and content creators, we must instill trust in our users with the goal of making them feel comfortable using our applications and ultimately giving up some of their personal info.</p>

<p>How often do you give away your personal information just because somebody asks for it, but not really knowing what they will do with it? You know what I'm talking about. Signing up for that "free" magazine subscription. Giving your phone number to the cashier when buying that new movie. Plugging in your email to receive order status updates about that $1.49 cable you bought from a company you never heard of but saw on SlickDeals. Like you, I've done all of these. But not without thinking twice about it.</p>

<p>As application developers, we have insight on both sides: consumers signing up for online services, and building our own services for others to use. When building services, you're in one of two camps: those that harness their users' info for marketing purposes, or those that don't. Regardless of where you fall, you have a responsibility to be transparent and open about how you intend to use or not use the data you're given. And how you present your site design, sign up forms and privacy policy (if you have one) play an important role in how much info your users will trust you with.</p>

<h3>Tell your users in simple terms: <em>Your data is safe with us</em></h3>

<p>I'm going to guess the majority of us building unique web applications aren't in the market of sharing our users' data with a third-party. We just need a way to track them in our <code>user</code> table. But how do our users know this?</p>

<p>Sure, they could read the privacy policy, but nobody <em>wants</em> to wade through legalese. There are a million apps out there I could sign up for. I just want to use the app. Let me in. Check. Done. But when given a long privacy policy, I can't help but think, "&hellip;I don't know what I'm agreeing to, but I'll give these guys the benefit of the doubt."</p>

<p>I feel much better if I'm given a friendly note on the sign up form: "We don't share your info, promise!" In fact, I will usually trust a company <em>even more</em> if they come right out and say it, rather than hiding behind a privacy policy checkbox.</p>

<p>Of course, if you're shooting for the "next big thing" status, you'll eventually need a legalese privacy policy. But why not give the full legal version, <em>and</em> a cliff notes version? (Hello, mortgage industry?)</p>

<h3>Tell your users what is going to happen, and do it</h3>

<p>When presented with a sign-up form, another thought goes through my mind: "Will I need to verify my email address?" Depending on what I think might happen, I will either give up my @hotmail address (spam-friendly) or my more personal @gmail address.</p>

<p>If you tell your users what is going to happen, and actually follow through on it, you <strong>automatically</strong> build trust. "Hey! They did what they said they would!" If your user needs to confirm their email address after submitting the form, tell them. Set expectations and set yourself up to meet them.</p>

<h3>Ask for all required info on your Register form</h3>

<p>If you really, really need a user's address and phone number to start an account, make it obvious. Give a little red * or REQUIRED next to your required fields.</p>

<p>The absolute worst thing a company could do is present a simple Register form (Name, Email, Password), require e-mail verification, then after verifying the address with a URL, <em>require</em> the user to give up their Mailing Address, Phone Number and Birthday before fully activating their account.</p>

<p>Not only will you likely increase the number of "@*\$# you" occurrences in your database, but you are asking users to jump through yet another hoop to use your site. All fields should be on one form with required fields noted, so the user can quickly see which info is required, and if they want to give it to you.</p>

<p>Make the barrier for entry as low as possible. Don't get roped into the backwards old-media ways of thinking! It is not the user's privilege to use your site: it is YOUR privilege that they have chosen to use your site. Without your users, your site doesn't exist.</p>

<h3>Don't create more work for the user</h3>

<p>If the user clicks Submit and has to correct a few fields, you're not doing your job as a data filterer or a form architect. And you're certainly not building trust. Even if the user enters the wrong info and has to re-complete some fields, they WILL BLAME YOU for not making it more obvious.</p>

<p>This means setting proper labels for your form fields, using color or size to denote required fields and not overwhelming the user. Don't give them a chance to become distracted. You want them to complete your form the first time through instead of making 3 round trips to the server. This not only slows them down from jumping in and using your application, but detracts from the confidence and trust the user has in your application's ability to work correctly and in the way they intend.</p>

<h3>User Testing and Production Analysis</h3>

<p>A lot of the pitfalls discussed here can be prevented with proper user testing and good feedback questions asked of your test users. Don't just focus on objective data: "How quickly did the user complete the form?" Pull questions on the <strong>emotions</strong> the user felt when first looking at the site, and after completing registration. "On a scale of 1-5, how much do you trust this company to abide by what they say? To store your data? To perform how you expect?"</p>

<p>The flip side is gathering statistical analysis of your production data after launch. If the bounce rate for your Registration form is high, something is scaring people away. Does your website appear friendly? Is your form well-laid out? Can a user quickly skim through it? Do you treat your users like a humans or spam bots? (Is your CAPTCHA harder than Contra?)</p>

<p>Usage statistics won't tell the full story. What is your clean record to dirty record ratio? Are you collecting real data or are users entering gibberish? Re-evaluate. Do you <em>absolutely need</em> the info you're requesting?</p>

<h3>Further Reading</h3>

<p>The following are must-reads for architecting web forms and general web content with a slant towards usability and building users' trust.</p>

<ul>
<li><a href="http://www.smashingmagazine.com/2008/07/04/web-form-design-patterns-sign-up-forms/">Web Form Design Patters: Sign-Up Forms</a> - Smashing Magazine</li>
<li><a href="http://www.amazon.com/Think-Common-Sense-Approach-Usability/dp/0789723107">Don't Make Me Think</a> - Steve Krug</li>
<li><a href="http://www.useit.com/alertbox/">Jakob Nielsen's Alertbox: Current Issues in Web Usability</a></li>
<li><a href="http://www.smashingmagazine.com/2009/02/03/clear-and-effective-communication-in-web-design/">Clear And Effective Communication In Web Design</a> - Smashing Magazine</li>
<li><a href="http://webjackalope.com/archive/lazy-registration">12 Excellent Examples of "Lazy Registration"</a> - Web Jackalope</li>
</ul>


<p>Feel free to leave additional reading recommendations or other ideas in the comments. What methods do you go through when laying out your web forms? Is your development front-end test-heavy, or more reliant on A/B results in production?</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[How to upgrade a Symfony project from 1.2 to 1.3/1.4]]></title>
            <link>http://johnkary.net/blog/how-to-upgrade-a-symfony-project-from-1-2-to-1-31-4/</link>
            <comments>http://johnkary.net/blog/how-to-upgrade-a-symfony-project-from-1-2-to-1-31-4/#disqus_thread</comments>
            <pubDate>Tue, 01 Dec 2009 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[php]]></category><category><![CDATA[symfony]]></category><category><![CDATA[tutorial]]></category>
            <guid>http://johnkary.net/blog/how-to-upgrade-a-symfony-project-from-1-2-to-1-31-4</guid>
            <description><![CDATA[Today, the Symfony crew has released Symfony 1.3 and 1.4. I recently deployed a pretty basic 1.2 app, and decided to try upgrading it to 1.3, and then on to 1.4, just to see if these “easy upgrade” claims were as advertised.<br><br>I will be following the 1.2 to 1.3/1.4 Upgrade Instructions below, so you should read over them before we get started.]]></description>
            <content:encoded><![CDATA[<p>Today, the Symfony crew has <a href="http://symfony.com/blog/a-week-of-symfony-152-23-29-november-2009">released Symfony 1.3 and 1.4</a>. I recently deployed a pretty basic 1.2 app, and decided to try upgrading it to 1.3, and then on to 1.4, just to see if these "easy upgrade" claims were as advertised.</p>

<p>I will be following the <a href="http://symfony.com/legacy/doc/tutorial/1_4/en/upgrade">1.2 to 1.3/1.4 Upgrade Instructions</a> below, so you should read over them before we get started.</p>

<hr />

<h3>Step 0: Create a new branch in your version control checkout for this new version</h3>

<p>If you're not using version control, now might be a good time to learn. I am using Subversion for this specific project, but suggest you look at git. The rest of this post will give examples using Subversion for keeping your project up to date.</p>

<p>Let's create a new branch from our trunk to handle upgrading to 1.3.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">svn copy http://svn.example.com/repo/trunk http://svn.example.com/repo/branches/symfony1_3 -m &quot;Creating branch of trunk to upgrade to Symfony 1.3.&quot;</span></code></pre></figure></p>

<p>Checkout your new branch to your development environment and let's get started.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">svn co http://svn.example.com/repo/branches/symfony1_3 ~/Sites/myproject/symfony1_3</span>
<span class="go">cd !$</span></code></pre></figure></p>

<hr />

<h3>Step 1: Check for 1.3 versions of your plug-ins</h3>

<p>Many core plugins were recently updated for 1.3, so check the <a href="http://svn.symfony-project.com/plugins/">plugin repository</a> for a 1.3 branch. (Some plugins may work without modification, but this is a case-by-case basis.)</p>

<p>Your plugins may not be as well maintained. Depending on how critical your plugin functionality, you may not be able to continue upgrading at this time.</p>

<p>In my case, I was only using the <a href="http://www.symfony-project.org/plugins/sfFormExtraPlugin">sfFormExtraPlugin plugin</a> to add some a multi-choice options to my forms.</p>

<hr />

<h3>Step 2: Update Symfony core files to 1.3</h3>

<p>Our Symfony core files live in <code>symfony1_3/lib/vendor/symfony</code>. I had manually installed the core files from a ZIP archive when I started developing the project, so they were not yet using <a href="http://svnbook.red-bean.com/en/1.0/ch07s03.html">svn:externals</a>.</p>

<p>We will remove the old 1.2 files and install the core files from the central 1.3 repository branch. By referencing the 1.3 branch, every time we execute <code>svn up</code>, our Symfony core libraries are updated to the newest version. This may or may not be the best solution in your case. If you do not want your core libraries automatically updated, reference one of Symfony's <a href="http://svn.symfony-project.com/tags/">RELEASE tags</a>.</p>

<p>Since the application I developed is not a critical application, I chose to live on the edge and reference the 1.3 branch.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">svn rm lib/vendor/symfony</span>
<span class="go">svn propedit svn:externals lib/vendor&lt;/p&gt;</span>

<span class="go">&lt;p&gt;symfony http://svn.symfony-project.com/branches/1.3/&lt;/p&gt;</span>

<span class="go">&lt;p&gt;svn commit . -m &quot;Remove Symfony 1.2 core libraries. Install Symfony 1.3 core libraries via svn:externals.&quot;</span>
<span class="go">svn up</span></code></pre></figure></p>

<hr />

<h3>Step 3: Get newest plugin versions</h3>

<p>You can try to update your plugins via the traditional <code>php symfony
plugin:upgrade yourPluginNameHere</code>, or check the <a href="http://svn.symfony-project.com/plugins/">plugin repository</a> for a 1.3 branch or 1.3-compatible development in the trunk.</p>

<p><em>sfWidgetFormPlugin</em> has a 1.3 branch, so again, let's remove the old plugin and link up the new one. My previous version was installed via the traditional <code>php symfony plugin:install sfFormExtraPlugin</code> command, so it should first be uninstalled, deleted, then linked up with an <code>svn:externals</code> reference.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">php symfony plugin:uninstall sfFormExtraPlugin</span>
<span class="go">svn rm plugins/sfFormExtraPlugin</span>
<span class="go">svn propedit svn:externals plugins&lt;/p&gt;</span>

<span class="go">&lt;p&gt;sfFormExtraPlugin http://svn.symfony-project.com/plugins/sfFormExtraPlugin/branches/1.3/&lt;/p&gt;</span>

<span class="go">&lt;p&gt;svn commit . -m &quot;Update sfFormExtraPlugin to 1.3-compatible branch.&quot;</span>
<span class="go">svn up</span></code></pre></figure></p>

<p>Repeat this process for all of your plugins that have new versions
available.</p>

<hr />

<h3>Step 4: Upgrading your project code to 1.3</h3>

<p>Running this command will automatically upgrade your code base to
Symfony 1.3.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">php symfony project:upgrade1.3</span>
<span class="go">svn commit . -m &quot;Upgraded project to Symfony 1.3.&quot;</span></code></pre></figure></p>

<h4>Doctrine 1.0 to Doctrine 1.2</h4>

<p>Assuming you are using <a href="http://www.doctrine-project.org/">Doctrine</a> as your ORM, Symfony 1.3/1.4 also upgrades Doctrine from 1.0 to 1.2. You will need to manually check your code against the upgrade documentation for <a href="http://svn.doctrine-project.org/tags/1.1.0/UPGRADE_TO_1_1">Doctrine 1.0 to 1.1 Upgrade</a> and <a href="http://svn.doctrine-project.org/tags/1.2.0/UPGRADE_TO_1_2">Doctrine 1.1 to 1.2 Upgrade</a>.</p>

<p>In my project, I was using a few non-static methods that had been changed to static methods in Doctrine 1.2.</p>

<h4>Propel 1.3 to Propel 1.4</h4>

<p><a href="http://propelorm.org/">Propel</a> ORM has also been updated to Propel 1.4 in Symfony 1.3/1.4. Check <a href="http://trac.propelorm.org/wiki/Documentation/1.4">Propel's Documentation</a> for any new changes.</p>

<hr />

<h3>Step 5: Rebuild your models/forms/filters and clear the cache</h3>

<p>With all our code updated, it's time to run the gauntlet of updating our forms, filters and models.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">php symfony doctrine:build --all-classes php symfony cache:clear</span></code></pre></figure></p>

<hr />

<h3>Step 6: Test your site in the browser</h3>

<p>Load up the dev environment for your application in your browser and cross your fingers :) Check the Web Debug bar and see that you're running on Symfony 1.3.0 and the version of your ORM.</p>

<div class="image">
    <img src="/images/posts/symfony-debug-toolbar-1.3.0.png" title="Symfony 1.3 Debug Toolbar" width="500">
</div>


<p>Assuming everything works, commit back to SVN.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">svn commit . -m &quot;Fully upgraded to Symfony 1.3.&quot;</span></code></pre></figure></p>

<hr />

<h3>Step 7: Check for deprecated code using <code>project:validate</code></h3>

<p>Now that our project is up to date with Symfony 1.3, we need to prepare to move it to Symfony 1.4. Fabien recently added an amazingly helpful command <a href="http://symfony.com/blog/upgrading-to-symfony-1-4">project:validate</a> that checks your code for use of deprecated code that has been removed for Symfony 1.4. Running the command against your project gives a list of deprecated classes in use and their location.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">php symfony project:validate</span></code></pre></figure></p>

<div class="image">
    <img src="/images/posts/php-symfony-project-validate.png" title="php symfony project:validate output" width="500">
</div>


<p>Since I started writing this project on Symfony 1.2.8, and this is a relatively straightforward project, there is not much to change. If you started from 1.0 or 1.1, there is undoubtedly a lot more code to change.</p>

<p>Most of the deprecated code above appears in the <code>/base/</code> directory of the Doctrine-generated code, which will be fixed when we regenerate our models/forms/filters.</p>

<h3>Fixing Deprecated Code</h3>

<h4>sfWidgetFormDoctrineChoiceMany</h4>

<p><code>project:validate</code> found one use of <code>sfWidgetFormDoctrineChoiceMany</code> in <code>EventForm.class.php</code>. Since I redefined my Event form in the <code>EventForm::configure()</code> method, I need to find the fix for using this deprecated class.</p>

<p>After checking the <a href="http://symfony.com/legacy/doc/tutorial/1_3/en/deprecated">Deprecated Code page for 1.3</a>, the <code>*Many()</code> form widgets have been deprecated. <code>sfWidgetFormDoctrineChoiceMany</code> has been consolidated into the <code>sfWidgetFormDoctrineChoice</code> class by adding the option <code>array('multiple' =&gt; true)</code> to denote a multi-select.</p>

<p>Symfony 1.2:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setWidgets</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
    <span class="s1">&#39;keywords_list&#39;</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nx">sfWidgetFormDoctrineChoiceMany</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
        <span class="s1">&#39;model&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;Keyword&#39;</span><span class="p">,</span>
        <span class="s1">&#39;renderer_class&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;sfWidgetFormSelectDoubleList&#39;</span><span class="p">,</span>
    <span class="p">)),</span>
<span class="p">));</span></code></pre></figure></p>

<p>Symfony 1.3:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setWidgets</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
    <span class="s1">&#39;keywords_list&#39;</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nx">sfWidgetFormDoctrineChoice</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
        <span class="s1">&#39;model&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;Keyword&#39;</span><span class="p">,</span>
        <span class="s1">&#39;renderer_class&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;sfWidgetFormSelectDoubleList&#39;</span><span class="p">,</span>
        <span class="s1">&#39;multiple&#39;</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">,</span>
    <span class="p">)),</span>
<span class="p">));</span></code></pre></figure></p>

<h4>sfValidatorDoctrineChoiceMany</h4>

<p>Since I was using a deprecated form widget, I also double-checked the widget's validator for the same field. [sfValidatorDoctrineChoiceMany][] has <em>not</em> been deprecated. Instead, it calls its parent <code>configure()</code> method in its parent class <code>sfValidatorDoctrineChoice</code>, and sets the option <code>multiple</code> to true.</p>

<p>Sounds very similar to the explanation above, doesn't it? Why the developers chose to deprecate the widget and not the validator, I'm not sure. Regardless, I chose to change <code>sfValidatorDoctrineChoiceMany</code> just to stay consistent with my form widget.</p>

<p>Symfony 1.2:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setValidators</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
    <span class="s1">&#39;keywords_list&#39;</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nx">sfValidatorDoctrineChoiceMany</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
        <span class="s1">&#39;model&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;Keyword&#39;</span><span class="p">,</span>
        <span class="s1">&#39;required&#39;</span> <span class="o">=&gt;</span> <span class="k">false</span><span class="p">,</span>
    <span class="p">)),</span>
<span class="p">));</span></code></pre></figure></p>

<p>Symfony 1.3:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setValidators</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
    <span class="s1">&#39;keywords_list&#39;</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nx">sfValidatorDoctrineChoice</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
        <span class="s1">&#39;model&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;Keyword&#39;</span><span class="p">,</span>
        <span class="s1">&#39;required&#39;</span> <span class="o">=&gt;</span> <span class="k">false</span><span class="p">,</span>
        <span class="s1">&#39;multiple&#39;</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">,</span>
    <span class="p">)),</span>
<span class="p">));</span></code></pre></figure></p>

<h4>sfCompat10Plugin</h4>

<p><code>sfCompat10Plugin</code> is also deprecated in Symfonry 1.4, so we must
remove all references to it. In my case, I had excluded it from loading in myproject/config/ProjectConfiguration.class.php.</p>

<p>Symfony 1.2:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">enableAllPluginsExcept</span><span class="p">(</span><span class="k">array</span><span class="p">(</span><span class="s1">&#39;sfPropelPlugin&#39;</span><span class="p">,</span> <span class="s1">&#39;sfCompat10Plugin&#39;</span><span class="p">));</span></code></pre></figure></p>

<p>Symfony 1.3:</p>

<p><figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">enableAllPluginsExcept</span><span class="p">(</span><span class="k">array</span><span class="p">(</span><span class="s1">&#39;sfPropelPlugin&#39;</span><span class="p">));</span></code></pre></figure></p>

<p>At this point, we have removed all deprecated code and are ready to
upgrade our project to Symfony 1.4! Commit our latest changes.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">svn commit . -m &quot;Removed deprecated code for Symfony 1.4.&quot;</span></code></pre></figure></p>

<h3>Step 8: Upgrade to Symfony 1.4</h3>

<p>Once again, you should check if your plugins have Symfony 1.4 versions, and update their <code>svn:external</code> references to their 1.4 branches.</p>

<p>If you plugin does not have a 1.4 version, the 1.3 version may work without modification. If the <code>project:validate</code> task does not return any deprecated code used in plugins, you may be clear.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">svn propedit svn:externals&lt;/p&gt;</span>

<span class="go">&lt;p&gt;plugins #Update your repo URLs to their 1.4 branches&lt;/p&gt;</span>

<span class="go">&lt;p&gt;svn up</span></code></pre></figure></p>

<p>With our Symfony core libraries referenced via <code>svn:externals</code>, we also need to update that reference to the Symfony 1.4 branch.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">svn propedit svn:externals lib/vendor&lt;/p&gt;</span>

<span class="go">&lt;p&gt;symfony http://svn.symfony-project.com/branches/1.4/&lt;/p&gt;</span>

<span class="go">&lt;p&gt;svn up</span></code></pre></figure></p>

<p>Now regenerate our forms, filters and models.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">php symfony doctrine:build --all-classes</span>
<span class="go">php symfony cache:clear</span></code></pre></figure></p>

<p>And assuming everything works, commit everything back to our development branch!</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">svn commit . -m &quot;Upgraded to Symfony 1.4. Whew!&quot;</span></code></pre></figure></p>

<p>Congratulations! You are now working with the latest version of Symfony 1.4!</p>

<hr />

<p>Well that <em>was</em> rather painless! You may or may not agree depending on how much legacy code you are maintaining :)</p>

<p>Congratulations to Fabien Potencier, Fabien Lange, Jonathan Wage, Kris Wallsmith and everyone who submitted patches to make this release possible!</p>

<p>With your new Symfony 1.4 install, why not start learning some of the more advanced tutorials in the <a href="http://symfony.com/blog/one-more-thing">Symfony 2009 Advent Calendar</a>?</p>
]]></content:encoded>
        </item>



        <item>
            <title><![CDATA[Fixing Evernote Error "The file Evernote.sql could not be opened."]]></title>
            <link>http://johnkary.net/blog/fixing-evernote-error-the-file-evernote-sql-could-not-be-opened/</link>
            <comments>http://johnkary.net/blog/fixing-evernote-error-the-file-evernote-sql-could-not-be-opened/#disqus_thread</comments>
            <pubDate>Sun, 22 Nov 2009 00:00:00 -0600</pubDate>
            <dc:creator>John Kary</dc:creator>
            <category><![CDATA[software]]></category>
            <guid>http://johnkary.net/blog/fixing-evernote-error-the-file-evernote-sql-could-not-be-opened</guid>
            <description><![CDATA[I’ve been having a battery/power issue with my MacBook Pro recently where it will turn off if the battery power has much less than 0:10 minutes left. You know, after the “You are running on Reserve Power” message comes up, but before it fully drains and (normally) puts itself to sleep using SafeSleep. So what do these power issues have to do with Evernote? A lot if your notes database becomes corrupted.]]></description>
            <content:encoded><![CDATA[<div class="image">
    <img src="/images/posts/evernote.png" title="Evernote error" width="500">
</div>


<p>I've been having a battery/power issue with my MacBook Pro recently where it will turn off if the battery power has much less than 0:10 minutes left. You know, after the "You are running on Reserve Power" message comes up, but before it fully drains and (normally) puts itself to sleep using <a href="http://support.apple.com/kb/HT1757?viewlocale=en_US">SafeSleep</a>.</p>

<p>So what do these power issues have to do with <a href="https://evernote.com/">Evernote</a>?</p>

<p>I experienced at least one said power failure while working on a note from Evernote's Mac Desktop client. From our days of using Windows, we all know power failures without proper shutdown lead to corrupted files on the hard drive. And that's exactly what happened here: a corrupted notes database file.</p>

<p>After launching Evernote, I would get an error saying, <code>The file "Evernote.sql" could not be opened.</code> Assuming you have recently sync'd your notes so that everything is on the Evernote server, here's how to fix it:</p>

<ol>
<li>Quit Evernote. Force quit if you have to.</li>
<li>Open Terminal.</li>
<li>Issue this command to remove your Evernote application settings and notes database directory:</li>
</ol>


<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">rm -rd ~/Library/Application\ Support/Evernote</span></code></pre></figure></p>

<p>Now re-launch Evernote. Your notes database and all settings will be downloaded from the Evernote server.</p>

<p>Easier fix than I anticipated. Here are the messages from my Console, in case it helps you find this page via Google.</p>

<p><figure class="highlight"><pre><code class="language-console" data-lang="console"><span></span><span class="go">11/22/09 10:10:20 PM Evernote[301] Client name: Evernote Mac/62233 (en-US); MacOS/10.5.8;</span>
<span class="go">11/22/09 10:10:21 PM Evernote[301] WebKit runtime: 531.21.8</span>
<span class="go">11/22/09 10:10:21 PM Evernote[301] WebCore runtime: 531.21.8</span>
<span class="go">11/22/09 10:10:21 PM Evernote[301] Safari clipper plugin version is 62229</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] NSInternalInconsistencyException thrown inside CoreData.</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] NSInternalInconsistencyException thrown inside CoreData.</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] NSInternalInconsistencyException thrown inside CoreData.</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] I/O error for database at /Users/johnkary/Library/Application Support/Evernote/data/51783/Evernote.sql.  SQLite error code:1, &#39;SQL logic error or missing database&#39;</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] I/O error for database at /Users/johnkary/Library/Application Support/Evernote/data/51783/Evernote.sql.  SQLite error code:1, &#39;SQL logic error or missing database&#39;</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] NSInternalInconsistencyException thrown inside CoreData.</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] NSInternalInconsistencyException thrown inside CoreData.</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] NSInternalInconsistencyException thrown inside CoreData.</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] Presenting error: Error Domain=NSCocoaErrorDomain Code=256 UserInfo=0x1543b310 &quot;The file ?Evernote.sql? could not be opened.&quot;</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301] Presenting error: Error Domain=NSCocoaErrorDomain Code=256 UserInfo=0x1543b310 &quot;The file ?Evernote.sql? could not be opened.&quot;</span>
<span class="go">11/22/09 10:10:22 PM Evernote[301]   user info: {</span>
<span class="go">NSFilePath = &quot;/Users/johnkary/Library/Application Support/Evernote/data/51783/Evernote.sql&quot;;</span>
<span class="go">NSLocalizedDescription = &quot;The file \U201cEvernote.sql\U201d could not be opened.&quot;;</span>
<span class="go">NSStackTraceKey = &quot;0x37419a  0x92289e3b  0x917a1f1a  0x917a45ab  0x9179d24c  0x91795d20  0x91795a27  0x91794aba  0x9179208b  0x962d8338  0x9617a6cb  0x962d7863  0x962d78e9  0x96406e5e  0x961edafc  0x9478d91d  0x9478d308  0x9478d3d8  0x939ae88e  0x9470e8f5  0x9470eaa8  0x9505f2ac  0x9505f0c5  0x9505ef39  0x95dd86d5  0x95dd7f88  0x95dd0f9f  0x95d9e1d8  0x2aea  0x2&quot;;</span>
<span class="go">NSUnderlyingError = Error Domain=NSCocoaErrorDomain Code=256 UserInfo=0x154dfbc0 &quot;The file ?Evernote.sql? could not be opened.&quot;;</span>
<span class="go">NSUnderlyingException = I/O error for database at /Users/johnkary/Library/Application Support/Evernote/data/51783/Evernote.sql.  SQLite error code:1, &#39;SQL logic error or missing database&#39;;</span>
<span class="go">}</span></code></pre></figure></p>
]]></content:encoded>
        </item>



    </channel>
</rss>
