<?xml version="1.0" encoding="utf-8" ?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <id>http://localhost:4242/</id>
  <title>http://localhost:4242</title>
  <updated>2015-12-23T14:00:44-05:00</updated>
  <link href="http://localhost:4242/blog.atom" rel="self" type="application/atom+xml" />
  <link href="http://localhost:4242/" rel="alternate" type="text/html" />
  <entry>
    <id>http://localhost:4242/blog/2015/12/23/The-Decommissioning-of-Onslyde.html</id>
    <title>The Decommissioning of Onslyde</title>
    <updated>2015-12-23T14:00:44-05:00</updated>
    <published>2015-12-23T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2015/12/23/The-Decommissioning-of-Onslyde.html" rel="alternate" type="text/html" />
    <category term="oss management"></category>
    <summary>
      As a creator and overseer of an Open Source project, we must make tough decisions on when to pull the plug and move on. In 2012,
      I started a web based, real-time feedback project called Onslyde.
      
      
      
      To me the project was a huge success with many measurable results:
      
      
      Massive amount of research with WebSockets and mobile devices.
      Based on the code and research I was able to craft many talks for speaking engagements at conferences around the globe.
      The Onslyde service was used at some of the most popular software engineering conferences. (e.g. EdgeConf 2013-2014)
      I received an incredible job offer that I unfortunately had to...
    </summary>
    <content type="html">
      &lt;p&gt;As a creator and overseer of an Open Source project, we must make tough decisions on when to pull the plug and move on. In 2012,
      I started a web based, real-time feedback project called &lt;a href=&quot;http://wesleyhales.com/blog/2013/02/25/How-Collective-Wisdom-Shapes-a-Talk/&quot;&gt;Onslyde&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;&lt;img style=&quot;max-width:90%&quot; src=&quot;http://localhost:4242/images/posts/2015-12-23/edge1-panel-detail-large-opt.png&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;To me the project was a huge success with many measurable results:&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;Massive amount of research with WebSockets and mobile devices.&lt;/li&gt;
      &lt;li&gt;Based on the code and research I was able to craft many talks for speaking engagements at conferences around the globe.&lt;/li&gt;
      &lt;li&gt;The Onslyde service was used at some of the most popular software engineering conferences. (e.g. EdgeConf 2013-2014)&lt;/li&gt;
      &lt;li&gt;I received an incredible job offer that I unfortunately had to turn down this time last year. massive salary, director title, bonus, everything...&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;All of the above and much more were the result of an open source side project on github. Of course, I had a few big fails
       along the way but overall I feel the project did something special that no one else was doing. It connected the audience with the
       conversation that has always been a one way lecture.&lt;/p&gt;
      
      &lt;p&gt;Anywho, here's to a great (almost) 4 year run for a project that I actually enjoyed working on. I may take the wisdom and lessons
      learned to a new similar project in 2016, so stay tuned.&lt;/p&gt;
      
      &lt;p&gt;Further Reading and Videos:&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;http://coding.smashingmagazine.com/2013/11/20/reinventing-the-tech-conference-experience/&quot;&gt;Smashing Magazine Article&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://wesleyhales.com/blog/2013/02/25/How-Collective-Wisdom-Shapes-a-Talk/&quot;&gt;Research on Audience Interaction&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://labs.ft.com/2013/10/thoughts-from-edge-2/&quot;&gt;Onslyde in use at EdgeConf 2&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://wesleyhales.com/blog/2014/02/26/A-More-Better-Conference-Experience/&quot;&gt;Onslyde in use at Devnexus 2014&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.christianheilmann.com/2014/03/22/edgeconf-3-just-be-there-next-time-trust-me/&quot;&gt;Onslyde in use at EdgeConf 3&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;
      &lt;a href=&quot;http://eventtech.co/2014/01/24/wesley-hales-creator-of-onslyde/&quot;&gt;EventTech podcast interview&lt;/a&gt;.&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;br&gt;
      
      
      &lt;br&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2015/04/24/Speedgun.html</id>
    <title>Simulated RUM testing with PhantomJS 2</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2015-04-24T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2015/04/24/Speedgun.html" rel="alternate" type="text/html" />
    <category term="web performance"></category>
    <category term="speedgun"></category>
    <summary>
      Today, many companies are synthetically measuring web performance with various scripts and services. Now that everyone is able to measure those performance numbers and visualize the problem areas, it’s time to raise the bar in terms of scalability, portability and the use of newer DOM APIs.
      
      The following charts show a snapshot of data collected over the period of one year (2012-2013) from the CNN.com home page using Loadreport.js.
      
      
      Loadreport data from 2012-2013 for CNN.com
      
      
      I started the Loadreport project while working on the CNN homepage in 2012. It was one of the first PhantomJS scripts that was built solely to collect as...
    </summary>
    <content type="html">
      &lt;p&gt;Today, many companies are synthetically measuring web performance with various scripts and services. Now that everyone is able to measure those performance numbers and visualize the problem areas, it’s time to raise the bar in terms of scalability, portability and the use of newer DOM APIs.&lt;/p&gt;
      
      &lt;p&gt;The following charts show a snapshot of data collected over the period of one year (2012-2013) from the CNN.com home page using &lt;a href=&quot;https://github.com/wesleyhales/loadreport&quot;&gt;Loadreport.js&lt;/a&gt;.
      &lt;a href=&quot;https://speakerdeck.com/wesleyhales/a-baseline-for-web-performance-with-phantomjs&quot;&gt;&lt;img style=&quot;max-width:90%&quot; src=&quot;http://localhost:4242/images/posts/2015-15-24/image05.png&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;div style=&quot;width:100%;text-align:center;font-style:italic;&quot;&gt;Loadreport data from 2012-2013 for CNN.com&lt;/div&gt;
      
      
      &lt;p&gt;I started the Loadreport project while working on the CNN homepage in 2012. It was one of the first PhantomJS scripts that was built solely to collect as many perf numbers from the DOM as possible. &lt;br&gt;
      However, the performance numbers collected from events like DOMContentLoaded, onload, and others are all based around old, inaccurate or poorly measured JavaScript APIs provided by the DOM.&lt;/p&gt;
      
      &lt;p&gt;These measurements were a great start and gave us some kind of baseline, but as the Web Performance industry has grown over the last several years, more understanding has been gained and better tools and dashboards are being written.&lt;br&gt;
      Now, &lt;a href=&quot;http://en.wikipedia.org/wiki/Real_user_monitoring&quot;&gt;Real User Monitoring (RUM)&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Synthetic_monitoring&quot;&gt;Synthetic Monitoring&lt;/a&gt;, &lt;a href=&quot;https://www.google.com/search?q=client+side+performance&amp;amp;oq=client+side+performance&amp;amp;aqs=chrome..69i57j0l5.347j0j7&amp;amp;sourceid=chrome&amp;amp;es_sm=91&amp;amp;ie=UTF-8&quot;&gt;Client Side Performance&lt;/a&gt; and many more terms seek to describe this way of capturing web performance and providing some kind of actionable insights around the data.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Enter Speedgun&lt;/h2&gt;
      
      &lt;p&gt;PhantomJS 2, released this year with a newer version of WebKit, implements the &lt;a href=&quot;http://www.w3.org/TR/2012/REC-navigation-timing-20121217/#sec-navigation-timing-interface&quot;&gt;Navigation Timing API&lt;/a&gt; specification giving us the ability to measure page performance in an automated fashion. Now we have microsecond precision around a much more robust set of APIs. This is why I rewrote Loadreport.js and named it Speedgun - to utilize the newer APIs and refactor a lot of things that didn’t work quite right… and because the Loadreport name was not super cool. It’s the classic story of rebranding an open source project :)
      The rest of this article reviews the details of how speedgun.js extracts and stores performance data across many different regions and nodes to achieve a Simulated RUM environment.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;What is Simulated RUM?&lt;/h2&gt;
      
      &lt;p&gt;I don’t know. It’s a frankenstein term where I’m trying to depict a remote control environment that represents real users. This environment should have:&lt;/p&gt;
      
      &lt;ol&gt;
      &lt;li&gt;The ability to execute a script (PhantomJS in this case) in a controlled, one at a time manner.&lt;/li&gt;
      &lt;li&gt;A REST api that allows master/slave communication and is publicly accessible.&lt;/li&gt;
      &lt;li&gt;A beacon that sends it’s availability to a centralized(parent) server.&lt;/li&gt;
      &lt;li&gt;Data storage of reports in a db that treats JSON as a first class citizen.&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;p&gt;All of these requirements have been built into &lt;a href=&quot;http://speedgun.io&quot;&gt;speedgun.io&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;After starting development of speedgun with Docker I realized that this could be easily distributed to any geographic region as a virtualized RUM node. I wanted to execute on the idea that this testing tool could be setup on an old mac mini at grandma’s house with a DSL connection.
      &lt;img style=&quot;max-width:90%&quot; src=&quot;http://localhost:4242/images/posts/2015-15-24/image00.png&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;Or, with a &lt;a href=&quot;https://github.com/wesleyhales/speedgun/blob/master/server/README.md&quot;&gt;simple git clone and execution of one command&lt;/a&gt;, it can be run on Digital Ocean, AWS, and more environments in every region.
      &lt;img style=&quot;max-width:90%&quot; src=&quot;http://localhost:4242/images/posts/2015-15-24/image01.png&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;Today, there are 2 available nodes to run a Speedgun report, DigitalOcean SF and NY. Hopefully there will be more in the list by the time you read this ;)
      &lt;a href=&quot;http://speedgun.io&quot;&gt;&lt;img style=&quot;max-width:90%&quot; src=&quot;http://localhost:4242/images/posts/2015-15-24/image04.png&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;h2&gt;The Speedgun API&lt;/h2&gt;
      
      &lt;p&gt;There are 2 parts to the speedgun REST API...&lt;/p&gt;
      
      &lt;p&gt;1) Creating and retrieving reports&lt;/p&gt;
      
      &lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;table&quot;&gt;
          &lt;tbody&gt;
          &lt;tr class=&quot;c13&quot;&gt;
              &lt;td class=&quot;c15&quot; colspan=&quot;2&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c17 c14&quot;&gt;Start a report&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Method&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
      &lt;p class=&quot;c2&quot;&gt;&lt;span&gt;http://localhost:8081/rest/performance/go&lt;/span&gt;&lt;/p&gt;
      
                  
      
                  &lt;p class=&quot;c5 c0&quot;&gt;&lt;span class=&quot;c8&quot;&gt;Parameters:&lt;/span&gt;&lt;/p&gt;
      
                  &lt;p class=&quot;c5 c0&quot;&gt;&lt;span class=&quot;c8&quot;&gt;url, cached, email&lt;/span&gt;&lt;/p&gt;
      &lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c5 c0&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Example&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
      &lt;p class=&quot;c5 c0&quot;&gt;&lt;span&gt;http://localhost:8081/rest/performance/go?cached=false&amp;amp;email=&amp;amp;url=http:%2F%2Fwww.google.com&lt;/span&gt;&lt;/p&gt;
      
                  &lt;p class=&quot;c5 c0 c4&quot;&gt;&lt;span class=&quot;c8&quot;&gt;&lt;/span&gt;&lt;/p&gt;
      &lt;/td&gt;
          &lt;/tr&gt; 
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Response&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8&quot;&gt;JSON - with uuid and status of where this report is in the queue&lt;/span&gt;
              &lt;/p&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c13&quot;&gt;
              &lt;td class=&quot;c15&quot; colspan=&quot;2&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c17 c14&quot;&gt;Retrieve a report&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Method&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
      &lt;p class=&quot;c5 c0&quot;&gt;&lt;span&gt;http://localhost:8081/rest/performance/report&lt;/span&gt;&lt;/p&gt;
      
                  &lt;p class=&quot;c5 c0&quot;&gt;&lt;span class=&quot;c8&quot;&gt;Parameters&lt;/span&gt;&lt;/p&gt;
      
                  &lt;p class=&quot;c5 c0&quot;&gt;&lt;span class=&quot;c8&quot;&gt;uuid (returned from “Start a report”)&lt;/span&gt;&lt;/p&gt;
      &lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Example&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span&gt;http://localhost:8081/rest/performance/report?uuid=62990112-48fc-4a95-bf32-2a09acf67dcd&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Response&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8&quot;&gt;JSON - All speedgun report data (except screenshots)&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;/tbody&gt;
      &lt;/table&gt;
      
      
      
      
      &lt;br&gt;
      
      
      &lt;p&gt;2) Beacon service&lt;/p&gt;
      
      &lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;table&quot;&gt;
          &lt;tbody&gt;
          &lt;tr class=&quot;c13&quot;&gt;
              &lt;td class=&quot;c15&quot; colspan=&quot;2&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c14 c17&quot;&gt;Start the beacon&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2 c10&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Method&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
      &lt;p class=&quot;c0 c5&quot;&gt;&lt;span class=&quot;c8&quot;&gt;http://localhost:8081/rest/beacon/init&lt;/span&gt;&lt;/p&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2 c10&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Response&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c5 c0&quot;&gt;&lt;span class=&quot;c8&quot;&gt;text/plain Notification message&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c13&quot;&gt;
              &lt;td class=&quot;c15&quot; colspan=&quot;2&quot; rowspan=&quot;1&quot;&gt;
      &lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c17 c14&quot;&gt;Retrieve list of available RUM nodes&lt;/span&gt;&lt;/p&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Method&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c5 c0&quot;&gt;&lt;span&gt;http://speedgun.io/rest/beacon/&lt;/span&gt;&lt;span class=&quot;c8&quot;&gt;getlist&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr class=&quot;c3&quot;&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8a&quot;&gt;Response&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
              &lt;td class=&quot;c9&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;c2&quot;&gt;&lt;span class=&quot;c8&quot;&gt;JSON - This gives us the JSON data for displaying available clients on the UI.&lt;/span&gt;
              &lt;/p&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;/tbody&gt;
      &lt;/table&gt;
      
      
      &lt;br&gt;&lt;br&gt;
      
      
      &lt;h3&gt;About the beacon service&lt;/h3&gt;
      
      &lt;p&gt;By default this is turned off. To start sending your beacon with system information to the central speedgun.io server, you only have to curl or load this url in your browser http://localhost:8081/rest/beacon/init.&lt;/p&gt;
      
      &lt;p&gt;The beacon sends the following data to the speedgun server every 60 seconds.
      &lt;img style=&quot;max-width:90%&quot; src=&quot;http://localhost:4242/images/posts/2015-15-24/image03.png&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;The only caveat to this working correctly is opening the required port on the firewall of the client machine’s network. You don’t have to open the port to send the beacon, only to allow speedgun reports to be ran by the centralized server.&lt;/p&gt;
      
      &lt;p&gt;Here’s a netgear router admin UI example:
      &lt;img style=&quot;max-width:90%&quot; src=&quot;http://localhost:4242/images/posts/2015-15-24/image02.png&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;After you open up port 8081 on your firewall, speedgun reports can be remotely ran from anywhere. Currently the speedgun.io URL is hardcoded as the centralized server, this will soon be broken out to a configuration file.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Why?&lt;/h2&gt;
      
      &lt;p&gt;Why on earth would I want to set this up or standup a speedgun node? A few good reasons…. First, having a consistent and stable environment to run browser performance testing is a must. Second, having the ability to run multiple tests from many different geographic locations with varying connections speeds is hard to simulate.
      Speedgun gives us both of these.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Futures&lt;/h2&gt;
      
      &lt;p&gt;&lt;a href=&quot;https://github.com/wesleyhales/speedgun/issues&quot;&gt;The issues list&lt;/a&gt; will give you an idea of where the project is heading. If you have any ideas or input feel free to leave them there.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Contributors&lt;/h2&gt;
      
      &lt;p&gt;It was also an honor to have a few performance gurus from the community helping out with this. Thanks goes to:
      Peter Hedgenskog who created &lt;a href=&quot;http://www.sitespeed.io/&quot;&gt;sitespeed.io&lt;/a&gt; and speaks at a ton of conferences about web performance. And Jarrod Overson author of &lt;a href=&quot;http://jsoverson.github.io/plato/examples/jquery/&quot;&gt;Plato&lt;/a&gt; and the new O’Reilly &lt;a href=&quot;http://www.amazon.com/Developing-Web-Components-jQuery-Polymer/dp/1491949023&quot;&gt;Web Components book&lt;/a&gt;!&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Other Page Testing Services&lt;/h2&gt;
      
      &lt;p&gt;I also want to give a quick shout out to all the other page testing services.&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://speedcurve.com/&quot;&gt;Speedcurve&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://www.webpagetest.org/&quot;&gt;WebPageTest.org&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://www.sitespeed.io/&quot;&gt;Sitespeed.io&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;and many others...&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;br&gt;
      
      
      &lt;h3&gt;References:&lt;/h3&gt;
      
      &lt;ul&gt;
      &lt;li&gt;Nav timing 2012 &lt;a href=&quot;http://www.w3.org/TR/2012/REC-navigation-timing-20121217/#sec-navigation-timing-interface&quot;&gt;http://www.w3.org/TR/2012/REC-navigation-timing-20121217/#sec-navigation-timing-interface&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://updates.html5rocks.com/2012/08/When-milliseconds-are-not-enough-performance-now&quot;&gt;http://updates.html5rocks.com/2012/08/When-milliseconds-are-not-enough-performance-now&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;HR Time (2012) &lt;a href=&quot;http://www.w3.org/TR/hr-time/#dom-performance-now&quot;&gt;http://www.w3.org/TR/hr-time/#dom-performance-now&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;MDN Nav timing &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Navigation_timing&quot;&gt;https://developer.mozilla.org/en-US/docs/Navigation_timing&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;Resource timing confusion &lt;a href=&quot;http://www.stevesouders.com/blog/2014/11/25/serious-confusion-with-resource-timing/&quot;&gt;http://www.stevesouders.com/blog/2014/11/25/serious-confusion-with-resource-timing/&lt;/a&gt;
      &lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;br&gt;
      
      
      &lt;br&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2014/02/26/A-More-Better-Conference-Experience.html</id>
    <title>A More Better Conference Experience</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2014-02-26T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2014/02/26/A-More-Better-Conference-Experience.html" rel="alternate" type="text/html" />
    <category term="devnexus"></category>
    <category term="onslyde"></category>
    <category term="raspberry pi"></category>
    <category term="rpi"></category>
    <summary>
      
      
      
      Overview
      
      I've been working on an open source project called Onslyde for almost 2 years. If you want to know the
      details behind it you can read articles here, here or watch a recent interview.
      
      This year, at Devnexus 2014, I wanted to take Onslyde a bit further by offering a way for sponsors to
      ask questions throughout the day between sessions. Since this was a trial/experiment I went old school and
      didn't create a web interface for reserving sponsored slots. I simply created a spreadsheet with speaker name, session title,
      and time. Sponsors could then choose a time and I would reserve it on a...
    </summary>
    <content type="html">
      &lt;br&gt;
      
      
      &lt;h2&gt;Overview&lt;/h2&gt;
      
      &lt;p&gt;I've been working on an open source project called &lt;a href=&quot;https://www.onslyde.com/&quot;&gt;Onslyde&lt;/a&gt; for almost 2 years. If you want to know the
      details behind it you can read articles &lt;a href=&quot;http://coding.smashingmagazine.com/2013/11/20/reinventing-the-tech-conference-experience/&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;http://wesleyhales.com/blog/2013/02/25/How-Collective-Wisdom-Shapes-a-Talk/&quot;&gt;here&lt;/a&gt; or &lt;a href=&quot;http://eventtech.co/2014/01/24/wesley-hales-creator-of-onslyde/&quot;&gt;watch a recent interview&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;This year, at &lt;a href=&quot;http://devnexus.com/&quot;&gt;Devnexus 2014&lt;/a&gt;, I wanted to take Onslyde a bit further by offering a way for sponsors to
      ask questions throughout the day between sessions. Since this was a trial/experiment I went old school and
      didn't create a web interface for reserving sponsored slots. I simply created a &lt;a href=&quot;https://docs.google.com/spreadsheet/ccc?key=0AnSCILK6XyYLdHVEdndSY1VCM2NSOFowNzZrb284a3c&amp;amp;usp=drive_web#gid=0&quot;&gt;spreadsheet&lt;/a&gt; with speaker name, session title,
      and time. Sponsors could then choose a time and I would reserve it on a first-come-first-serve basis.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;The Idea&lt;/h2&gt;
      
      &lt;p&gt;At it's core, Onslyde is a tool that allows people to connect and give their opinion within seconds. Now,
      attendees can vote on seeded questions that will allow sponsors to connect to those who are truly interested
      in their product or what they have to say.&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://localhost:4242/images/posts/2014-02-26/image_3.jpeg&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2014-02-26/image_3.jpeg&quot; class=&quot;margin10 max-width-50 float-right&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;I've already written about &lt;a href=&quot;http://coding.smashingmagazine.com/2013/11/20/reinventing-the-tech-conference-experience/&quot;&gt;the disconnect between speakers and attendees&lt;/a&gt;, but what about the disconnect
      between sponsors and attendees? After all, these are the companies that shell out massive amounts of cash, setup up
      a booth, and wait for attendees to visit them in hopes of gaining a lead, recruiting a new employee, or making a sell.
      Why not proactively give them true leads that don't require a stop by the ol' exhibit floor booth?&lt;/p&gt;
      
      &lt;p&gt;This all sounds great in theory, but I had no idea how hard this would be to put together and manage throughout
      a 2 day conference with around 1200 attendees. So let's look at the details behind the implementation and
      challenges that were faced.&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;p&gt;Devnexus had around 30 sponsors this year. This included Red Hat, GitHub, Twilio, and many others. I wanted a
      way for them to communicate with attendees who are interested in what they have to say on the screen.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;We started out by allowing each sponsor to ask one question, and then charging a fee for additional questions.
      However, and I'm happy about it now, zero paid slots were sold. But almost all the sponsors took advantage of their one free question, so a week before the
      conference we ended up giving all the slots away for free.
      I quickly learned that trying to sell the empty slots was the wrong approach - mainly because it requires up front sales.
      Either myself or someone else would need to try and up sell sponsors on question slots. It was too much selling without proven results.&lt;/p&gt;&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;In hindsight, I should've given sponsors a limit of 10 questions/slots and then found a way to expose the voting
      data in a freemium model.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;The Hardware&lt;/h2&gt;
      
      &lt;p&gt;I used a fairly cheap hardware setup powered by Raspberry Pis (or RPi). For around $80, we had a complete Onslyde powered device
      that could be placed in any of the rooms. Devnexus had 10 simultaneous tracks, or rooms where someone was speaking, plus
      a workshop track. So we needed 10 rooms to be setup with the RPis for live voting.&lt;/p&gt;
      
      &lt;p&gt;The hardware setup consisted of the following:&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;Raspberry Pi (model B)&lt;/li&gt;
      &lt;li&gt;16GB SD Card&lt;/li&gt;
      &lt;li&gt;Edimax wifi USB device&lt;/li&gt;
      &lt;li&gt;HDMI to VGA converter dongle&lt;/li&gt;
      &lt;li&gt;3ft VGA cable&lt;/li&gt;
      &lt;li&gt;VGA 2 way push-button splitter&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;&lt;a href=&quot;http://localhost:4242/images/posts/2014-02-26/image.jpeg&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2014-02-26/image.jpeg&quot; class=&quot;margin10 max-width-50 float-left&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;The last item in the list above is what caused me a lot of trouble. Ultimately the hardware setup was solid and worked
      really well. But physically pushing the button to switch between voting and speakers ready to present was impossible to
      handle manually.&lt;/p&gt;
      
      &lt;p&gt;Remember we're talking about 10 tracks spread throughout a very large conference center, so after each session the
      halls would be packed with people and I was weaving in and out of a stream of attendees trying to get to the next room. I would
      have literally needed a volunteer in each room pressing buttons as sessions rotate.&lt;/p&gt;
      
      &lt;p&gt;The next section will go over all the challenges I faced, but the main point I want to make here is that it's pretty incredible
      to power one of the largest developer conferences in the South East with a $45 piece of hardware and a little bit of open source.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Challenges&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;As I just mentioned, the physical aspect of pushing a button to switch video streams limited how many sponsored questions
      were actually seen and voted on. The only way around this would be to create a video switcher that would automatically detect the video
      current from the speaker and override the secondary Onslyde RPi signal. This is definitely doable and if something doesn't exist that already
      handles this case, then I'm assuming it wouldn't be hard to break out the soldering iron and rig something together.&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;&lt;a href=&quot;http://localhost:4242/images/posts/2014-02-26/image_9.jpeg&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2014-02-26/image_9.jpeg&quot; class=&quot;margin10 max-width-100 float-left&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;p&gt;The Raspberry Pi's boot to a stripped down Debian based operating system that goes straight into full screen Chromium. The browser then
      loads a unique onslyde address with the RPis network interface (wlan0) mac address as a query parameter. This was the most generic
      way of identifying the device from my server and keeping track of its location. So, this obviously requires internet access but the conference
      center required authentication before making it out to the internet.
      Overall the staff at this particular venue were super helpful, so I asked if I could have the 10 mac addresses for the RPis whitelisted. This
      would allow them to access the internet without authentication. It was totally doable, but they wanted $200 per mac address to do it! I luckily
      talked them into doing it for $200 for all 10, but it's crazy to see the hoops that conference organizers have to jump through at the last minute.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Working with the A/V team wasn't too much of a challenge, but I had to prepare ahead of time for longer VGA cables. They ran
      extra long VGA cables from the projector and the podium to the back of the room. This allowed easy access to each Onslyde device as I ran
      in each room switching the projector to the Onslyde screen, and then switching it back 15 minutes later to the presenter.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;One thing that would've been nice is a web UI to handle the scheduling and input of sponsored questions. Since I was trying to prove the
      idea, there wasn't much of a reason to invest in the development until I knew it worked. But, if sponsors could come to a page, login,
      and see documentation and videos about the advantages of the product, then it would've prevented any doubt and probably would've secured more
      interest and questions.&lt;/p&gt;&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Conclusion&lt;/h2&gt;
      
      &lt;p&gt;Overall, I can honestly say that I learned a ton from this experience. We all have these grand ideas of how something should work and
       how cool it will be, but until you get out and actually try it, you have no idea.&lt;/p&gt;
      
      &lt;p&gt;Below are &lt;a href=&quot;https://www.onslyde.com/#!/analytics?sessionID=555&quot;&gt;the results&lt;/a&gt; from one of the polls that was asked during a morning session:
      &lt;a href=&quot;http://localhost:4242/images/posts/2014-02-26/devnexus-voting.png&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2014-02-26/devnexus-voting.png&quot; class=&quot;margin10 max-width-100&quot;&gt;&lt;/a&gt;
      You can probably imagine, at this point, what you would do with this data as a sponsor. When each user votes they are required to oauth with their G+
      account. So we have names and email addresses that can be contacted after the fact.&lt;/p&gt;
      
      &lt;p&gt;My plans for the future are to investigate if this is worth continuing and make the bootable Onslyde Debian image freely available.
      Feel free to &lt;a href=&quot;https://docs.google.com/document/d/1STZ6gzOBLPnUypwHtFGZQY9ME7lYK__DpoQcKFzeLV0/edit#heading=h.hnil29ggb4vc&quot;&gt;review my notes&lt;/a&gt; on the exact hardware I used and how I setup
      the devices to boot into full screen Chromium and run Onslyde.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;br&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2013/12/17/Designing-and-Implementing-an-Angular-Dashboard.html</id>
    <title>From Startup to Enterprise</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2013-12-17T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2013/12/17/Designing-and-Implementing-an-Angular-Dashboard.html" rel="alternate" type="text/html" />
    <category term="design"></category>
    <category term="develop"></category>
    <category term="angularjs"></category>
    <summary>
      
      
      
      Overview
      
      At the beginning of 2013 I was given the incredible opportunity to start with an empty canvas and come up with a completely new web application for Apigee.
      For the past year I've been heads down on merging Apigee's Usergrid and Mobile Analytics products using AngularJS.
      
      For those interested: Usergrid, a
      Backend as a Service, was acquired by Apigee in early 2012 and has served as the core tool of all Apigee trainings and developer outreach efforts.
      Developers use it to create a backend for their mobile apps amongst many other things like managing users, roles and permissions.
      The Mobile Analytics product is something I...
    </summary>
    <content type="html">
      &lt;br&gt;
      
      
      &lt;h2&gt;Overview&lt;/h2&gt;
      
      &lt;p&gt;At the beginning of 2013 I was given the incredible opportunity to start with an empty canvas and come up with a completely new web application for Apigee.
      For the past year I've been heads down on merging Apigee's Usergrid and Mobile Analytics products using AngularJS.&lt;/p&gt;
      
      &lt;p&gt;For those interested: Usergrid, a
      Backend as a Service, was acquired by Apigee in early 2012 and has served as the core tool of all Apigee trainings and developer outreach efforts.
      Developers use it to create a backend for their mobile apps amongst many other things like managing users, roles and permissions.
      The Mobile Analytics product is something I was partial to since I created the original UI - before it was acquired by Apigee. I wanted to carry it past
      the acquisition and endure the process of turning it into a full fledged enterprise offering.&lt;/p&gt;
      
      &lt;p&gt;This is a retrospective - carrying an idea from startup to enterprise product.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Let's start with the design&lt;/h2&gt;
      
      &lt;p&gt;We started brainstorming for the new UI on February 1st. Originally we set out to only deliver a new analytics dashboard, but were soon asked to merge
      the existing UserGrid project into the fold.&lt;/p&gt;
      
      &lt;p&gt;Here are the first designs and wireframes we came up with. I purposely left everything greyscale to allow for a pure focus on the page data and layout.&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://localhost:4242/images/posts/2013-12-17/first-design-a-large.png&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-12-17/first-design-a.png&quot; class=&quot;margin10 max-width-100 float-left&quot;&gt;&lt;/a&gt;
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-12-17/first-design-b-large.png&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-12-17/first-design-b.png&quot; class=&quot;margin10 max-width-100 float-left&quot;&gt;&lt;/a&gt;
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-12-17/first-design-c-large.png&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-12-17/first-design-c.png&quot; class=&quot;margin10 max-width-100 float-left&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;br class=&quot;clear-left&quot;&gt;
      
      
      &lt;p&gt;The layouts above took around 1 month to deliver, and many of the UI elements were reworked from the old UI. Most of the work went into the new look and feel and
      reformatting the data to appear more readable.&lt;/p&gt;
      
      &lt;p&gt;After the team was in agreement on how the pages should be structured, we then went into the finer design details. It's kind of weird (and welcomed) being the designer
      AND developer for a given project. I mean, that's what startups are all about - doing everything and playing all the roles - but when you get into larger
      companies and work with larger teams, people start to look at you a little funny and the criticism is a little heavier. And that's totally expected and
      understandable, because as companies grow it only makes sense to hire these things out to design firms that are doing this stuff day in and day out.&lt;/p&gt;
      
      &lt;p&gt;So navigation design is always a fun topic amongst developers and designers. Especially when some products use a horizontal design and others choose vertical.
      It really depends on the usecase on which way you should go. We went with the vertical menu in this case because the end user (developers) would be
      building an app with our UI. It only made sense to see and understand each tool we were providing on a visual level, and not hidden away in a horizontal menu with
      drop downs.&lt;/p&gt;
      
      &lt;p&gt;This is the evolution of our menu design in chronological order from left to right. Design is an iterative process for me and
      I never get it right on the first go. And it really helps to have good feedback from other &quot;design minded&quot; folks.&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://localhost:4242/images/posts/2013-12-17/menus-large.png&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-12-17/menus-large.png&quot; class=&quot;margin10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;I wanted to leave a lot of the original grey design from the mockups and not get too heavy handed with the colors. After all, we were
      building an analytics dashboard that needed to put heavy emphasis on errors, warnings, and other alerts.&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://localhost:4242/images/posts/2013-12-17/app-erros.png&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-12-17/app-erros.png&quot; class=&quot;margin10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;The style guide is still in the works. Luckily Apigee already had one, so I leveraged all the existing colors and fonts.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;The Code&lt;/h2&gt;
      
      &lt;p&gt;By mid-April, we had most of the feedback implemented into the wireframes and were ready to move forward with development. During
      this month and in between feedback rounds, I was evaluating both Ember and AngularJS. I'm not going to turn this into
      a discussion of which framework I think is better - they both have their strengths and weaknesses - but I will tell you why I
      went with Angular.&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;Community - When I opt for a framework, it has to be strongly backed by the community.&lt;/li&gt;
      &lt;li&gt;Components - I like the web components approach that Angular has going with directives. And putting heavy emphasis on this from the start was a good move by the
      Angular team. Directives, love or hate, are a huge win for gaining community support and contributions. I've also recently seen a few conference speakers focus their entire
      session on directives. Sure, there's a bit of a learning curve, but the concept is well received by most front-end devs.&lt;/li&gt;
      &lt;li&gt;Productivity - I liked being productive. This post is a testament to being productive, seeing that two developers could stand up an entire analytics and BaaS dashboard within 6 months.&lt;/li&gt;
      &lt;li&gt;Architecture - Angular sets forth the idea of a loosely coupled architecture for building large apps. The mechanisms for dependency injection and scope management were attractive to me.&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;On May 1st I had the markup and a beginning on the Angular architecture all pushed to github. From May into the late summer months we were
      busting ass trying to get this dashboard completed. I was mainly working on the global parts of the app along with the monitoring dashboard, and we had
      one other developer focusing on rewriting the existing Usergrid Backbone application into Angular.&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://localhost:4242/images/posts/2013-12-17/github.png&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-12-17/github.png&quot; style=&quot;width: 500px&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;On August 9th we had our first C-Level review of the beta version of the product. This is pretty significant seeing that two developers were
      able to produce a massive SPA in a little over 3 months. Not to mention managing vacation schedules and other things that arose. Of course,
      We still had a ways to go in polishing the application and not to mention testing, but overall we were able to get a lot done in a short
      amount of time.&lt;/p&gt;
      
      &lt;p&gt;Here are a couple of projects and articles that resulted from this work:
      &lt;/p&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/wesleyhales/angular-charts&quot;&gt;Angular Charts&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://wesleyhales.com/blog/2013/10/23/Basic-Screen-Updates-with-Angular-and-requestAnimationFrame/&quot;&gt;Basic Screen Updates with Angular and requestAnimationFrame&lt;/a&gt;&lt;/li&gt;
      
      &lt;h2&gt;Conclusion&lt;/h2&gt;
      
      &lt;p&gt;There are many reasons I like Angular for 2013, 2014, and maybe even 2015. But another framework will come in &amp;lt;= 3 years time, and it will be even more productive and we'll
       be rewriting a new product all over again. That's the nature of the beast and it's very similar to many other 3 year life cycles we see in the tech industry. Bottom line: Don't religiously buy into
       any web framework. Use it at face value and always be prepared for the next one.&lt;/p&gt;
      
      &lt;p&gt;Along the way, I had brilliant input and help from many awesome folks. The product manager for this effort was &lt;a href=&quot;https://twitter.com/karlunho&quot;&gt;Alan Ho&lt;/a&gt;, and I would not
      have been able to forge a usable product without his vision of how things should come together. &lt;a href=&quot;https://twitter.com/edanuff&quot;&gt;Ed Anuff&lt;/a&gt;, the founder of Usergrid, was truly a pleasure
      to work with/for and receive guidance from during many frustrating times. &lt;a href=&quot;https://twitter.com/prabhatjha&quot;&gt;Prabhat Jha&lt;/a&gt;, my long time pal worked tirelessly to setup the RESTful
      endpoints I needed to get the job done (along with countless other backend pieces). And last but not least, &lt;a href=&quot;https://twitter.com/rockerston&quot;&gt;Rod Simpson&lt;/a&gt; who stepped in to help with the
      Backbone-to-Angular rewrite of the existing UserGrid product. Rod also has an impressive design background and helped/pushed me to design a better product
      when I hit blocks.&lt;/p&gt;
      
      &lt;p&gt;You can try the dashboard out for yourself &lt;a href=&quot;https://apigee.com/usergrid&quot;&gt;here&lt;/a&gt;. Lemme know what you think!&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;br&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2013/10/26/Jank-Busting-Apples-Home-Page.html</id>
    <title>Jank Busting Apple's Home Page</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2013-10-26T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2013/10/26/Jank-Busting-Apples-Home-Page.html" rel="alternate" type="text/html" />
    <category term="jank"></category>
    <summary>
      
      
      
      Overview
      
      Watching frame rates on CSS and/or JavaScript animation is pretty addictive. I wrote this article the other day which examines the
      performance of a simple countdown timer within the Angular lifecycle. I then spent countless minutes playing
      Jake Archibald's Jank Invaders to hone my skills and save the universe from jank :)
      
      So, I was on Apple's home page the other day and noticed some jank in their main carousel animation.
      
      It wasn't anything huge, but the
      animation seemed to stagger a bit as the transitions were beginning and ending. There are five transitions that occur to display different
      Apple products. You can see this in...
    </summary>
    <content type="html">
      &lt;br&gt;
      
      
      &lt;h2&gt;Overview&lt;/h2&gt;
      
      &lt;p&gt;Watching frame rates on CSS and/or JavaScript animation is pretty addictive. I wrote &lt;a href=&quot;http://localhost:4242/blog/2013/10/23/Basic-Screen-Updates-with-Angular-and-requestAnimationFrame/&quot;&gt;this article&lt;/a&gt; the other day which examines the
      performance of a simple countdown timer within the Angular lifecycle. I then spent countless minutes playing
      Jake Archibald's &lt;a href=&quot;http://jakearchibald.github.io/jank-invaders/&quot;&gt;Jank Invaders&lt;/a&gt; to hone my skills and save the universe from jank :)&lt;/p&gt;
      
      &lt;p&gt;So, I was on &lt;a href=&quot;http://apple.com&quot;&gt;Apple's home page&lt;/a&gt; the other day and noticed some jank in their main carousel animation.
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-10-26/apple.home.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-26/apple.home.PNG&quot; alt=&quot;apple home page&quot; style=&quot;width:50%&quot; class=&quot;margin10&quot;&gt;&lt;/a&gt;
      It wasn't anything huge, but the
      animation seemed to stagger a bit as the transitions were beginning and ending. There are five transitions that occur to display different
      Apple products. You can see this in the Frame analysis below. Each green line shooting to 0 FPS is a &lt;a href=&quot;https://developers.google.com/chrome-developer-tools/docs/timeline#painting_events&quot;&gt;paint&lt;/a&gt; within chrome.
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-10-26/apple.com.jank.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-26/apple.com.jank.PNG&quot; alt=&quot;bad fps jank&quot; class=&quot;marginTop10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;Digging deeper, we can see that a large amount of time is being taken for the hardware compositing. This is where we force elements to be accelerated and
       handled by the GPU with translate3D(0,0,0) or translateZ(0) (aka &lt;a href=&quot;http://aerotwist.com/blog/on-translate3d-and-layer-creation-hacks/&quot;&gt;null transform hack&lt;/a&gt;).
       The problem with Apple's site and the reason why paints are spiking before each animation is because too many layers (or divs) have the null transform applied.
       &lt;img src=&quot;http://localhost:4242/images/posts/2013-10-26/composite.PNG&quot; alt=&quot;layer composite time&quot; class=&quot;margin10 max-width-100&quot;&gt;
       &lt;br&gt;
       I wrote about this &lt;a href=&quot;http://www.html5rocks.com/en/mobile/optimization-and-performance/&quot;&gt;a while ago&lt;/a&gt;, but the basic point is that too much of a good thing is often a bad thing. In this case, too many elements have translateZ(0)
       applied when only one or two applications are really needed. This is forcing a longer composite time and ultimately giving the animations some jank.&lt;/p&gt;
      
      &lt;p&gt; The fix is easy. Start with the top level container for the animation and see which of the child elements have a null transform and figure out if they really need it.
       If we turn on &quot;&lt;a href=&quot;http://updates.html5rocks.com/2013/02/Profiling-Long-Paint-Times-with-DevTools-Continuous-Painting-Mode&quot;&gt;Continuous Page Repainting&lt;/a&gt;&quot; in dev tools, we can see how the page is being painted and how many composited layers we have.
       &lt;a href=&quot;http://localhost:4242/images/posts/2013-10-26/apple-paint.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-26/apple-paint.PNG&quot; alt=&quot;bad fps jank&quot; class=&quot;marginTop10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt; By viewing the source and running through each element of the carousel animation, we can see that the parent already has the proper layer compositing.
       From there, I just disabled all the null transform hacks that were applied to nested elements.
       &lt;a href=&quot;http://localhost:4242/images/posts/2013-10-26/apple.markup.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-26/apple.markup.PNG&quot; alt=&quot;apple home page markup&quot; class=&quot;marginTop10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt; After doing this and fixing one other tiny CSS bug of one element having two different backgrounds, we get much better performance as you can see in the
       below timeline.
       &lt;a href=&quot;http://localhost:4242/images/posts/2013-10-26/apple.com.no.jank.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-26/apple.com.no.jank.PNG&quot; alt=&quot;apple home page markup&quot; class=&quot;marginTop10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt; The yellow bars are the 7 second timer before each transition occurs, so this is expected.&lt;/p&gt;
      
      &lt;p&gt; The animation on Apple.com isn't terrible as it stands in its current state, but as I stated at the beginning of this article, it's fun to fix jank :)&lt;/p&gt;
      
      &lt;p&gt; &lt;br&gt;
       &lt;br&gt;&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;br&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2013/10/23/Basic-Screen-Updates-with-Angular-and-requestAnimationFrame.html</id>
    <title>Basic Screen Updates with Angular and requestAnimationFrame</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2013-10-23T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2013/10/23/Basic-Screen-Updates-with-Angular-and-requestAnimationFrame.html" rel="alternate" type="text/html" />
    <category term="rAF"></category>
    <category term="requestAnimationFrame"></category>
    <category term="angular"></category>
    <category term="angularjs"></category>
    <category term="setinterval"></category>
    <category term="settimeout"></category>
    <category term="jank"></category>
    <summary>
      
      
      
      Overview
      
      Some of the best known approaches for running a countdown or count-up timer in AngularJS are shown on JSFiddle using setInterval and
      Angular's builtin $timeout.
      
      
      
      
      Both approaches require the use of $scope.$apply, which is completely normal. It forces the page/bindings to update when a change
      is made outside of the AngularJS lifecycle (like inside a setInterval or setTimeout).
      If you want to read more about $scope.$apply check out this article.
      
      For this particular case, I need a countdown timer on the page. Basically it sits in the upper right hand corner of the page and lets
      the user know when it's about to refresh the data.
      
      
      
      I...
    </summary>
    <content type="html">
      &lt;br&gt;
      
      
      &lt;h2&gt;Overview&lt;/h2&gt;
      
      &lt;p&gt;Some of the best known approaches for running a countdown or count-up timer in AngularJS are shown on JSFiddle using &lt;a href=&quot;http://jsfiddle.net/IgorMinar/ZSBhg/2/&quot;&gt;setInterval&lt;/a&gt; and
      Angular's builtin &lt;a href=&quot;http://jsfiddle.net/ganarajpr/LQGE2/&quot;&gt;$timeout&lt;/a&gt;.&lt;/p&gt;
      
      &lt;iframe width=&quot;100%&quot; height=&quot;300&quot; src=&quot;http://jsfiddle.net/IgorMinar/ZSBhg/2/embedded/&quot; allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
      
      
      &lt;p&gt;Both approaches require the use of $scope.$apply, which is completely normal. It forces the page/bindings to update when a change
      is made outside of the AngularJS lifecycle (like inside a setInterval or setTimeout).
      If you want to read more about $scope.$apply check out &lt;a href=&quot;http://jimhoskins.com/2012/12/17/angularjs-and-apply.html&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;For this particular case, I need a countdown timer on the page. Basically it sits in the upper right hand corner of the page and lets
      the user know when it's about to refresh the data.&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;https://apigee.com/usergrid/dash/app/index-ma.html&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-23/dashboard.PNG&quot; alt=&quot;apigee app services dashboard&quot; class=&quot;marginTop10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;I finally got a chance to analyze the performance of updating the page every second with a simple timer and couldn't believe how much jank it was causing.
      There are a lot of good articles and videos explaining jank and how to debug, but Paul Irish made a really good short video and I advise you
       check it out &lt;a href=&quot;http://www.youtube.com/watch?v=mSK70FwUz2A&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;If we look at the frame rate on the recommended way of using setInterval, we see horrible performance:
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-10-23/bad-fps.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-23/bad-fps.PNG&quot; alt=&quot;bad fps jank&quot; class=&quot;marginTop10 max-width-100&quot;&gt;&lt;/a&gt;
      Yep, That's 1 FPS spikes with a continuous stream of 9 frames per second. Ouch.&lt;/p&gt;
      
      &lt;p&gt;Also, if you look at the memory being consumed, we're taking quite a hit for this little counter.
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-10-23/bad-memory.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-23/bad-memory.PNG&quot; alt=&quot;bad fps jank&quot; class=&quot;marginTop10 max-width-100&quot;&gt;&lt;/a&gt;
      We maintain around 25MB and then shoot up to 34 when the page does its refresh.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;br&gt;
      
      
      &lt;h2&gt;rAF to the rescue!&lt;/h2&gt;
      
      &lt;p&gt;I'm still trying to bring requestAnimationFrame into my dev thought process, and this was a fine chance to see if it could save the day.
      Here's the code I put together:&lt;/p&gt;
      
      &lt;iframe width=&quot;100%&quot; height=&quot;300&quot; src=&quot;http://jsfiddle.net/wesleyhales/59SeE/embedded/&quot; allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
      
      
      &lt;p&gt;And now, when we look at our frame rate in Chrome dev tools we get a fairly consistent 60 FPS:
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-10-23/good-fps.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-23/good-fps.PNG&quot; alt=&quot;good fps&quot; class=&quot;marginTop10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;Also the memory footprint is greatly reduced:
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-10-23/good-memory.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-10-23/good-memory.PNG&quot; alt=&quot;good fps&quot; class=&quot;marginTop10 max-width-100&quot;&gt;&lt;/a&gt;
      Cruising at 9.3MB instead of the 25MB we were getting before bringing in rAF.&lt;/p&gt;
      
      &lt;p&gt;A lot of the performance overhead is based on the AngularJS framework itself. It could be stuff I need to refactor and make better or it might just be the
      framework lifecycle. I need to get a baseline on the AngularJS runtime before I can make any assumptions (or point fingers).
      This is my first perf analysis of the framework and I plan on doing much more in the coming months.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;br&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2013/03/29/Fun-with-Static-Site-Generators-and-Travis.html</id>
    <title>Fun with Static Site Generators and Travis</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2013-03-29T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2013/03/29/Fun-with-Static-Site-Generators-and-Travis.html" rel="alternate" type="text/html" />
    <category term="preprocessor"></category>
    <category term="travisci"></category>
    <category term="awestruct"></category>
    <category term="loadreportjs"></category>
    <summary>
      
      
      
      Overview
      
      If you use a static website generator, then you may be aware of the pain that goes into getting everything automated and pushed out to github pages on each commit.
      
      The manual workflow goes something like this:
      
      
      code your site using asciidoc/markdown/haml/sass/less/etc
      preprocessor (or build) generates static site (locally on your machine)
      copy static site to your local gh-pages or username.github.com repo/branch
      git push new site
      done
      
      
      
      Now, with a little scripting we can have:
      
      
      code your site using asciidoc/markdown/haml/sass/less/etc
      git push to source repo
      done (with so many other cool features at our fingertips)
      
      
      
      Most preprocessor tools do have some kind of built in function for this workflow, but when...
    </summary>
    <content type="html">
      &lt;br&gt;
      
      
      &lt;h2&gt;Overview&lt;/h2&gt;
      
      &lt;p&gt;If you use a static website generator, then you may be aware of the pain that goes into getting everything automated and pushed out to github pages on each commit.&lt;/p&gt;
      
      &lt;p&gt;The manual workflow goes something like this:&lt;/p&gt;
      
      &lt;ol&gt;
      &lt;li&gt;code your site using asciidoc/markdown/haml/sass/less/etc&lt;/li&gt;
      &lt;li&gt;preprocessor (or build) generates static site (locally on your machine)&lt;/li&gt;
      &lt;li&gt;copy static site to your local gh-pages or username.github.com repo/branch&lt;/li&gt;
      &lt;li&gt;git push new site&lt;/li&gt;
      &lt;li&gt;done&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;p&gt;Now, with a little scripting we can have:&lt;/p&gt;
      
      &lt;ol&gt;
      &lt;li&gt;code your site using asciidoc/markdown/haml/sass/less/etc&lt;/li&gt;
      &lt;li&gt;git push to source repo&lt;/li&gt;
      &lt;li&gt;done (with so many other cool features at our fingertips)&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;p&gt;Most preprocessor tools do have some kind of built in function for this workflow, but when you need to take it to a finer grained level and leverage services on the CI server, then this is what must be done.&lt;/p&gt;
      
      &lt;p&gt;With our new workflow, we let Travis CI do the work for us in a bash script. This opens the door to automation greatness for many other things like testing and asset uploads. As you will see at the end of this article, we add a simple PhantomJS script
      to test how each new commit loads (over time) in a web browser - giving us a baseline for site performance.&lt;/p&gt;
      
      &lt;p&gt;This post is going to review the basics of setting up your github OAuth token, encryption with travis, and finally pushing your website to github pages with an automated travisci build.
      We'll top it all off with running &lt;a href=&quot;http://loadreport.wesleyhales.com&quot;&gt;loadreport.js&lt;/a&gt; after each check in to understand how a single commit can affect site performance. So let's go...&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Github hosting setup&lt;/h2&gt;
      
      &lt;p&gt;If you're unfamiliar with github pages or how to host your own top-level domain (yourdomain.com) under your github account, then read &lt;a href=&quot;https://help.github.com/articles/what-are-github-pages&quot;&gt;this&lt;/a&gt;, &lt;a href=&quot;https://help.github.com/articles/creating-project-pages-manually&quot;&gt;then this&lt;/a&gt; first.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Github, Travis, and OAuth&lt;/h2&gt;
      
      &lt;p&gt;First off, you must login to &lt;a href=&quot;https://travis-ci.org&quot;&gt;Travis CI&lt;/a&gt; with your github username and enable the travis service hook on the repository you wish to automate.
      For me, this is where my haml/sass/etc... source is located.
      &lt;img src=&quot;http://localhost:4242/images/posts/2013-03-29/travisci1.png&quot; alt=&quot;travis&quot; class=&quot;margin10&quot;&gt;
      Next, we'll create an OAuth token for your repository access :&lt;/p&gt;
      
      &lt;script src=&quot;https://gist.github.com/wesleyhales/5274538.js&quot;&gt;&lt;/script&gt;
      
      
      &lt;p&gt;Pluck the &lt;b&gt;&quot;token&quot;:&lt;/b&gt; string value from the generated json and encrypt it. Pro tip: this token is basically the same thing as your password. So don't push it out to a public repository.&lt;/p&gt;
      
      &lt;script src=&quot;https://gist.github.com/wesleyhales/5274559.js&quot;&gt;&lt;/script&gt;
      
      
      &lt;p&gt;To encrypt, we must install the travis gem and encrypt the token string from above with:&lt;/p&gt;
      
      &lt;script src=&quot;https://gist.github.com/wesleyhales/5274580.js&quot;&gt;&lt;/script&gt;
      
      
      &lt;p&gt;..this will create a string in your console and we'll paste it below, so keep it close by...&lt;/p&gt;
      
      &lt;p&gt;Now, we can create the gh-pages branch for this repository &lt;a href=&quot;https://help.github.com/articles/creating-project-pages-manually&quot;&gt;following these instructions&lt;/a&gt;. This gh-pages branch can host your generated site or artifacts. Since I have a TLD mapped to my wesleyhales.github.com
      repository, I'm using the gh-pages branch under my source account for load testing reports. For my blog, I'm mapping a domain name over by simply forwarding a TLD like wesleyhales.com, with an A record pointing to 204.232.175.78.
      Then I added a &lt;a href=&quot;https://github.com/wesleyhales/wesleyhales.github.com/blob/master/CNAME&quot;&gt;CNAME file&lt;/a&gt; to the repo so github DNS knows where to forward to.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;The Build Config&lt;/h2&gt;
      
      &lt;p&gt;Finally, we're ready to update our .travis.yml.&lt;/p&gt;
      
      &lt;script src=&quot;https://gist.github.com/wesleyhales/5274500.js&quot;&gt;&lt;/script&gt;
      
      
      &lt;p&gt;&lt;a href=&quot;http://awestruct.org/getting_started/&quot;&gt;Awestruct&lt;/a&gt; is a ruby based preprocessor, so this project is setup with the travis ruby config (above).&lt;/p&gt;
      
      &lt;p&gt;Note the &lt;b&gt;before_script&lt;/b&gt; and &lt;b&gt;script&lt;/b&gt; configs:&lt;/p&gt;
      
      &lt;p&gt;&lt;b&gt;before_script&lt;/b&gt; runs the awestruct build and then the post_build.sh script. post_build.sh pushes our newly generated public facing website to github pages. This is where github kindly serves up our static content at username.github.com (for free).&lt;/p&gt;
      
      &lt;script src=&quot;https://gist.github.com/wesleyhales/5274512.js&quot;&gt;&lt;/script&gt;
      
      
      &lt;p&gt;And finally, &lt;b&gt;script&lt;/b&gt; will run gh-pages-report.sh. This allows us to run &lt;a href=&quot;http://loadreport.wesleyhales.com&quot;&gt;loadreport.js&lt;/a&gt; and send the generated report to our source gh-pages branch.
      Travis CI provides an instance of phantomjs during our build, so all we have to do is call it. This is basically a build report (or artifact from the build). It measures how long
      it takes our site to load after each commit is made. This gives us a baseline for measuring performance.&lt;/p&gt;
      
      &lt;script src=&quot;https://gist.github.com/wesleyhales/5274517.js&quot;&gt;&lt;/script&gt;
      
      
      
      
      &lt;br&gt;
      
      
      &lt;h2&gt;The Results&lt;/h2&gt;
      
      &lt;p&gt;The source for this blog you are reading is stored on github &lt;a href=&quot;https://github.com/wesleyhales/wesleyhales.com&quot;&gt;here&lt;/a&gt;. When I do
      a git push, everything is automatically built with travis and pushed again to the &lt;a href=&quot;https://github.com/wesleyhales/wesleyhales.github.com&quot;&gt;github repo&lt;/a&gt; that is specially named to handle the
      mapping of my TLD (wesleyhales.com) to my username on github.
      &lt;img src=&quot;http://localhost:4242/images/posts/2013-03-29/blog-ss.png&quot; class=&quot;margin10&quot; width=&quot;400px&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;Since I have 2 repositories, one for the preprocessor source and the other for the TLD mapping, I'm using the gh-pages branch on my
       source repository for reporting. With PhantomJS and loadreport.js, I run a test on every commit to see how I affected my sites loading performance.
       The results of this test are automatically pushed and I can view them &lt;a href=&quot;http://wesleyhales.com/wesleyhales.com/&quot;&gt;here&lt;/a&gt;.
       &lt;a href=&quot;http://wesleyhales.com/wesleyhales.com/&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-03-29/perf-test.png&quot; class=&quot;margin10&quot; width=&quot;400px&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt; From a UI polish perspective, I have a ton left to do. But the concept stays the same for any build. Use it to build and push out project
       documentation along with other reports and assets. I'd eventually like to write a script to do a diff on only test the pages that were changed on the commit.&lt;/p&gt;
      
      &lt;p&gt; &lt;br&gt;
       &lt;br&gt;&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2013/02/25/How-Collective-Wisdom-Shapes-a-Talk.html</id>
    <title>How Collective Wisdom Shapes a Talk</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2013-02-25T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2013/02/25/How-Collective-Wisdom-Shapes-a-Talk.html" rel="alternate" type="text/html" />
    <category term="websockets"></category>
    <category term="speaking"></category>
    <category term="audience engagement"></category>
    <summary>
      
      
      
      Overview
      
      Exactly one year ago, I started working on a WebSocket prototype that would give audiences the power to control
      my talks. I used it for the first time at DevNexus 2012 in Atlanta, GA and it produced great engagement results. At that time,
       the only analytics I had built into the server were through logging, and the results were motivating enough to continue using the prototype.
      Over the span of 2012, I spent many late nights in hotel rooms preparing my slides for talks and working out bugs of
      this tool which I named "onslyde". The following video is a talk I gave...
    </summary>
    <content type="html">
      &lt;br&gt;
      
      
      &lt;h2&gt;Overview&lt;/h2&gt;
      
      &lt;p&gt;Exactly one year ago, I started working on a WebSocket prototype that would give audiences the power to control
      my talks. I &lt;a href=&quot;http://wesleyhales.com/images/posts/2012-11-01/c70jx.jpg&quot;&gt;used it for the first time&lt;/a&gt; at DevNexus 2012 in Atlanta, GA and it produced great engagement results. At that time,
       the only analytics I had built into the server were through logging, and the results were motivating enough to continue using the prototype.&lt;br&gt;
      Over the span of 2012, I spent many late nights in hotel rooms preparing my slides for talks and working out bugs of
      this tool which I named &quot;onslyde&quot;. The following video is a talk I gave on February 18th, 2013 at the same conference one year later.
      Analytics were added and many bugs were fixed. I also integrated the tool with the reveal.js presentation framework. I had originally
       built a simple HTML+CSS slide deck, and by integrating with reveal.js, I was able to see that my code would integrate nicely with other
        presentation frameworks.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
      
      &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;http://www.youtube.com/embed/n-7Xu75T2bU&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
      
      
      &lt;br&gt;&lt;br&gt;
      
      
      &lt;p&gt;&lt;em&gt;Points in the talk where the audience voted:&lt;/em&gt;&lt;/p&gt;
      
      &lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=n-7Xu75T2bU#t=101s&quot;&gt;Vote 1&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=n-7Xu75T2bU#t=583s&quot;&gt;Vote 2&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=n-7Xu75T2bU#t=1571s&quot;&gt;Vote 3&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=n-7Xu75T2bU#t=1762s&quot;&gt;Vote 4&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=n-7Xu75T2bU#t=3451s&quot;&gt;Vote 5&lt;/a&gt;&lt;/li&gt;
      
      &lt;h2&gt;Details of onslyde&lt;/h2&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://localhost:4242/images/posts/2013-02-25/onslyde.arch.png&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-02-25/onslyde.arch.png&quot; alt=&quot;onslyde architecture&quot; class=&quot;margin10&quot; width=&quot;200px&quot; align=&quot;left&quot;&gt;&lt;/a&gt;
      At its core, the concept is simple. Attendees connect to a WebSocket server, the presenter sends them vote options at certain points during her
       presentation and whoever decides to connect can have anonymous interactions with the presenter. Participants may also give a
      &quot;thumb up&quot; or &quot;thumb down&quot; during any slide to show that they approve or disapprove of the content on a given slide. This allows for a
      very fine grained level of anonymous interaction.&lt;/p&gt;
      
      &lt;p&gt;Beyond the simplistic parts of interacting with the slide deck, I wanted the presenter to actually have the ability of tailoring their
      talk to the &quot;collective wisdom&quot; of the audience. So, the presenter has the ability of forking their slides and providing 2 tracks of
      content based on the audience vote. The poll and tracks are setup declaratively as follows:&lt;/p&gt;
      
      &lt;br&gt;&lt;br style=&quot;clear:left&quot;&gt;
      
      
      &lt;script src=&quot;https://gist.github.com/wesleyhales/5014482.js&quot;&gt;&lt;/script&gt;
      
      
      &lt;br&gt;
      
      
      &lt;ul&gt;
      &lt;li&gt;
      &lt;em&gt;data-option=&quot;master&quot;&lt;/em&gt; : denotes a master slide where the bar graph will be displayed&lt;/li&gt;
      &lt;li&gt;
      &lt;em&gt;data-option=&quot;Blue&quot;&lt;/em&gt; : is one of the 2 polling options&lt;/li&gt;
      &lt;li&gt;
      &lt;em&gt;data-option=&quot;Red&quot;&lt;/em&gt; : is one of the 2 polling options, also notice that we have multiple &quot;Red&quot; sections. These slides will be presented
      in order if &quot;Red&quot; wins the audience vote.&lt;/li&gt;
      &lt;li&gt;
      &lt;em&gt;class=&quot;send&quot;&lt;/em&gt; : specifies that we want to send this content to each connected remote&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;So, the above markup sets up the following slide deck and remote control options:
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-02-25/onslyde-1.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-02-25/onslyde-1.PNG&quot; alt=&quot;onslyde architecture&quot; class=&quot;margin10&quot; width=&quot;500px&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;After all the votes are placed, the winning track is chosen based on the majority vote:
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-02-25/onslyde-2.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-02-25/onslyde-2.PNG&quot; alt=&quot;onslyde architecture&quot; class=&quot;margin10&quot; width=&quot;500px&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;After the fork occurs, the presenter can choose to present slides in linear fashion, or ask another poll question. The framework is
      limited by only allowing for 2 options to be given and slides can only be forked once per question.&lt;/p&gt;
      
      &lt;p&gt;As stated earlier, everything is declarative and setup through HTML markup. So there's no need for the presenter to setup a server or mess
      with JavaScript. The deck can work without an internet connection as a fallback, or you could run the server on your laptop and bring
      a router/hotspot for the audience to connect to.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h2&gt;Analytics&lt;/h2&gt;
      
      &lt;p&gt;Mid last year, I started capturing audience data into a database. I also added Google analytics (with custom events) to the remotes so I could get a
      good understaning on audience devices and usage. The following data is from the video above.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h3&gt;From MySQL&lt;/h3&gt;
      
      &lt;p&gt;Here, we're capturing votes on the options and how many times the &quot;Nice&quot; and &quot;WTF&quot; buttons were pressed during this track. One thing that
      Google Analytics does not give us are timestamps, or when events occured at a fine grained level. By capturing the time when each &quot;Nice&quot;
       or &quot;WTF&quot; button is pressed, I can see exactly which slide was being shown and when the button was pressed. There is a bit of a latency
       issue from the time the button is pressed until the time it actually shows up on the presenters screen, so capturing the TS at the server
       level gives a more accurate picture of how you performed on each slide, if the content made sense, etc.
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-02-25/hypevreality.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-02-25/hypevreality.PNG&quot; alt=&quot;onslyde architecture&quot; class=&quot;margin10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;h3&gt;From GA and Custom Events&lt;/h3&gt;
      
      &lt;p&gt;This is an overview of the device analytics. I didn't want to reinvent the wheel on User Agent detection and keeping track of sessions, so I leveraged GA.
      The following data is from my talk, in the video above, given on February 18th.
      &lt;a href=&quot;http://localhost:4242/images/posts/2013-02-25/feb18Devnexus.PNG&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2013-02-25/feb18Devnexus.PNG&quot; alt=&quot;onslyde architecture&quot; class=&quot;margin10 max-width-100&quot;&gt;&lt;/a&gt;&lt;/p&gt;
      
      &lt;h2&gt;Conclusion&lt;/h2&gt;
      
      &lt;p&gt;&lt;em&gt;Become a better speaker&lt;/em&gt; &lt;br&gt;
      I know that I'm not a &quot;great&quot; public speaker. Sure I can hold my own, but I still have a lot to learn. And every person who gives a presentation
      is different. We all have different personalities, views, and ways of moving about the stage - we all have an idea of what we think the audience wants
       to know. But allowing the audience to guide the speaker and to anonymously give their input is huge. You won't get that kind of feedback verbally or
       by asking the audience to raise their hand for a given question. Nor will you get this type of fine grained feedback in a survey form at the end of your talk.&lt;br&gt;
      You might not be able to tell it, but in the video above, every time I ask the audience to vote on something and I look up at the
      responses coming in, it gives me a huge boost of confidence. Not just because the tool is actually being used, but I feel like I'm
      about to go down a road that is actually useful to them. At that point I adjust and tailor everything I say from the results that
      came in.&lt;/p&gt;
      
      &lt;p&gt;&lt;em&gt;Make the conversation go both ways&lt;/em&gt; &lt;br&gt;
      When an individual feels that they can control the presentation's future, it's a powerful thing. It's one thing just to poll the audience
      and get feedback, but to have a number of slides prepared for the results of that poll is another thing.
      Also, with the capabilities of mobile browsers today, we can make the presentation experience much richer. With this tool,
      I can send each person the notes and other information which relates to the slide I'm currently on. I can also send the ones who voted but didn't win the track selection, the slides or
      notes that I didn't show. So many possibilities to this...&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/bejug/8190387932/sizes/l/in/set-72157632019400699/&quot;&gt;&lt;img src=&quot;http://farm9.staticflickr.com/8348/8190387932_37343f3e53_n.jpg&quot; alt=&quot;onslyde architecture&quot; target=&quot;_blank&quot; class=&quot;margin10 max-width-100&quot; align=&quot;left&quot;&gt;&lt;/a&gt;
      Fortunately, I've had the chance to test this code/concept out in many different talks over the past year. From 10 people in a room to 100's,
       the feeling of having everyone dialed into what you're saying is invaluable.&lt;/p&gt;
      
      &lt;p&gt;&lt;em&gt;Crowdsourcing and forming some kind of collective wisdom&lt;/em&gt; &lt;br&gt;
      Using this tool at a conference allows for a limited number of attendees to participate, but taken to a larger scale (webinar), the combined thoughts
      of the audience on a given topic can be surprising. Not just to the presenter for tailoring his next steps, but to the data collected behind
       the scenes. Because my interests lie in the mobile web and HTML5, I get really interesting stats for devices and browsers with each talk I give.
       But, if I were a presenter introducing a new product (outside of the tech realm) and trying to sell it to the audience, I would have
       a huge advantage by allowing for impulse buys and fine grained sales throughout my talk. Basically, content would be spoon fed and the
       chance of missed opportunities would be slim.&lt;/p&gt;
      
      &lt;br&gt;&lt;br&gt;
      
      
      &lt;h2&gt;Open Source&lt;/h2&gt;
      
      &lt;p&gt;This presentation tool is open source. If you'd like to signup for the beta and give it a spin, I would greatly appreciate your feedback.
      This blog post is serving as the documentation for the project until I get some time to improve.&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;
      &lt;a href=&quot;http://onslyde.com&quot; target=&quot;_blank&quot;&gt;Signup here&lt;/a&gt; and get a session ID. Make a note of your assigned &quot;session ID&quot;. The UI sucks right now, so after you hit the submit button it will show up in a barely visible green box above the name input.&lt;/li&gt;
      &lt;li&gt;Follow the directions &lt;a href=&quot;http://onslyde.com/example-deck.html&quot; target=&quot;_blank&quot;&gt;mentioned in this slide deck&lt;/a&gt;. Basically just save the HTML to disk somewhere.&lt;/li&gt;
      &lt;li&gt;Go to line 317 in the HTML file you just saved and replace the current sessionID value (103) with the one from your signup.&lt;/li&gt;
      &lt;li&gt;You now have a private session for your presentation.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/wesleyhales/onslyde&quot;&gt;Come help out with the project&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;If you run into bugs, report them &lt;a href=&quot;https://github.com/wesleyhales/onslyde/issues&quot;&gt;here&lt;/a&gt; please.&lt;/p&gt;
      
      &lt;p&gt;Thanks!!&lt;/p&gt;
      
      &lt;br style=&quot;clear:left&quot;&gt;
      
      
      &lt;br&gt;&lt;br&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2013/02/18/Adventures-With-the-Skia-Debugger.html</id>
    <title>Adventures with the Skia Debugger</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2013-02-18T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2013/02/18/Adventures-With-the-Skia-Debugger.html" rel="alternate" type="text/html" />
    <category term="frontend"></category>
    <category term="html"></category>
    <category term="css"></category>
    <category term="graphics"></category>
    <category term="debug"></category>
    <summary>
      
      
      
      Debugging jank, reflows, etc...
      
      
      The Skia debugger was mentioned a few weeks ago at EdgeConf as a way to examine how the DOM is loaded and processed in the Chromium web browser. Skia is the open source C++ graphics library backing Chromium/Chrome. It comes with a graphical tool used to step through and analyze the contents of the skia picture format.
      
      If you haven’t watched this video, I recommend you take a few minutes and watch the first part to understand the context of why the Skia debugger was mentioned and where it might be useful. For the impatient, there was a...
    </summary>
    <content type="html">
      &lt;br&gt;
      
      
      &lt;h3&gt;Debugging jank, reflows, etc...&lt;/h3&gt;
      
      
      &lt;p&gt;The &lt;a href=&quot;https://sites.google.com/site/skiadocs/developer-documentation/skia-debugger&quot;&gt;Skia debugger&lt;/a&gt; was mentioned a few weeks ago at EdgeConf as a way to examine how the DOM is loaded and processed in the Chromium web browser. Skia is the open source C++ graphics library backing Chromium/Chrome. It comes with a graphical tool used to step through and analyze the contents of the skia picture format.&lt;/p&gt;
      
      &lt;p&gt;If you haven’t watched &lt;a href=&quot;http://www.youtube.com/watch?v=3-WYu_p5rdU&quot;&gt;this video&lt;/a&gt;, I recommend you take a few minutes and watch the first part to understand the context of why the Skia debugger was mentioned and where it might be useful. For the impatient, there was a lot of talk around image decoding and scrolling. This morphed into a discussion about bounce rates and how scrolling really matters from an experience standpoint. Basically, if you’re scrolling sucks, users do a lot less and bounce quicker.&lt;/p&gt;
      
      &lt;p&gt;Overall, it sparked my curiosity to see if I could get a visual understanding of reflow happening on web sites/apps... much like this FF3 reflow video from a few years ago.&lt;/p&gt;
      
      &lt;iframe width=&quot;420&quot; height=&quot;315&quot; src=&quot;http://www.youtube.com/embed/ZTnIxIA5KGw&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
      
      
      &lt;p&gt;Although the Skia debugger doesn't give us a nice video with animations (like shown above), it does give some really good info on how graphics are drawn into the browser.
      This &lt;a href=&quot;http://blog.mozilla.org/gen/2009/04/09/how-to-make-your-own-gecko-reflow-video/&quot;&gt;blog post&lt;/a&gt; explains how the above video was created with FF 3.1, but I’m not sure if anyone has attempted it with the latest Firefox build... and there is no visual debugger afaik. I did hear one of the panel members mention a Firefox “jank mode” but a short Google search turned up little results that don’t work on the latest version.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h3&gt;Building the debugger from source&lt;/h3&gt;
      
      
      &lt;p&gt;I will state upfront that there was a lot of pain that went into building both the debugger and chromium from source, but as you will see, it was worth it.&lt;/p&gt;
      
      &lt;p&gt;Here are my build notes for OSX 10.7.5:&lt;/p&gt;
      
      &lt;script src=&quot;https://gist.github.com/wesleyhales/4980385.js&quot;&gt;&lt;/script&gt;
      
      
      
      
      &lt;br&gt;
      
      
      &lt;h3&gt;Using the Debugger&lt;/h3&gt;
      
      
      &lt;p&gt;The debugger is fairly straightforward to use once a picture is loaded in. You can step through different commands via the up and down keys and clicking on the command in the list. You can also pause execution of commands with the pause button in order to inspect the details of the command in the inspector tabs down below.
      &lt;img src=&quot;http://localhost:4242/images/posts/2013-02-18/skia-ss.PNG&quot; alt=&quot;skia&quot; class=&quot;margin10 max-width-100&quot;&gt;
      Here are the available keyboard shortcuts for the debugger:
      &lt;img src=&quot;http://localhost:4242/images/posts/2013-02-18/skia-commands.PNG&quot; alt=&quot;skia&quot; class=&quot;margin10 max-width-100&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;After playing around with the debugger, it’s nice to get a very low level snapshot of how long it takes a specific browser to draw the pictures necessary to present a web page.&lt;/p&gt;
      
      &lt;p&gt;P.S. I plan on uploading my produced binaries (somewhere), so if you're on a Mac around version 10.7.5, hit me up @wesleyhales. Hopefully I can save a few poor souls a weekend full of building from sources ;)
      Happy debugging!&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2012/11/01/I-Will-Sleep-When-I-Die.html</id>
    <title>I'll Sleep When I Die - All for HTML5</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2012-11-01T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2012/11/01/I-Will-Sleep-When-I-Die.html" rel="alternate" type="text/html" />
    <category term="life"></category>
    <summary>
      The following post is a long-winded summary of my experiences over the past year. I started a user group, wrote a book,
      gave up a secure job, and changed jobs 4 times. All to push myself, get uncomfortable, and better understand the challenges
      that front-end developers are facing in 2012 and beyond. I gained more than I ever thought possible.
      
      Sometimes you have to give up everything to find something.
      
      Almost one year ago (September 2011), I started the HTML5 user group in Atlanta Georgia.
      This started as an experiment and outlet for me to practice my front-end related presentations. I really had no idea...
    </summary>
    <content type="html">
      &lt;p&gt;The following post is a long-winded summary of my experiences over the past year. I started a user group, wrote a book,
      gave up a secure job, and changed jobs 4 times. All to push myself, get uncomfortable, and better understand the challenges
      that front-end developers are facing in 2012 and beyond. I gained more than I ever thought possible.&lt;/p&gt;
      
      &lt;p&gt;Sometimes you have to give up everything to find something.&lt;/p&gt;
      
      &lt;p&gt;Almost one year ago (September 2011), I started the &lt;a href=&quot;http://www.meetup.com/AtlantaHTML5/&quot;&gt;HTML5 user group&lt;/a&gt; in Atlanta Georgia.
      This started as an experiment and outlet for me to practice my front-end related presentations. I really had no idea who
      would come or how fast the group would grow. But much to my surprise, the &lt;a href=&quot;http://www.meetup.com/AtlantaHTML5/events/29823121/&quot;&gt;first meetup&lt;/a&gt;
      brought out around 60 attendees. &lt;a href=&quot;http://wesleyhales.com/blog/2012/07/19/HTML5-in-Atlanta/&quot;&gt;One year later&lt;/a&gt;, the group has over 1200 members,
      5 awesome sponsors, and I am now connected to some of the coolest people, developers and thought leaders in the industry.
      I could write an entire blog post on this topic alone, but starting this group has been one of the most humbling experiences of my life.
      Many of the folks that come out to the meetups remind me of different stages that I’ve gone through in my career.
      Some are far ahead of me and are doing things that I really admire and others are just starting out and looking for work.
      Overall, I’ve learned that community creates technology. HTML5 and mobile have inspired developers and designers to think
      differently and do new amazing things, but in the end, it’s the developers and community who collectively see through the
      marketing hype of products and platforms to choose viable/useful solutions.&lt;/p&gt;
      
      &lt;p&gt;The month after starting Atlanta HTML5 (October 2011), &lt;a href=&quot;http://www.html5rocks.com/en/mobile/optimization-and-performance/&quot;&gt;an article that I’d been working on for months&lt;/a&gt;
      was finally published on html5rocks.com. It just so happened that the article went out the day before my presentation at JavaOne 2011.
      So everything aligned really nicely and the talk went well. This all leads up to me authoring a book.
      During my stay in SF, I was introduced to Meghan Blanchette who is an editor at O’Reilly. We started talking and I told
      her it would be cool to write a book. I casually agreed that I’d send her a proposal for a book that talks about
      HTML5 in the enterprise. After all, I come from a decade of heavy middleware stacks and server-side generated markup.
      So I thought my perspective might be valuable as developers make the transition to offline capable clients.&lt;/p&gt;
      
      &lt;p&gt;In November 2011, my proposal was accepted and I signed the O’Reilly contract for a book entitled “HTML5 Architecture”
      , which would later be renamed to &lt;a href=&quot;http://shop.oreilly.com/product/0636920024088.do&quot;&gt;“HTML5 and JavaScript Web Apps”&lt;/a&gt;.
      This was a huge personal step for me. At first it was very exciting and I was motivated to create the best HTML5 related
      book the world had ever seen. I committed to the fact that I would give up countless afternoons and weekends
      (away from my wife and kids) to research and write about the latest web technologies available to developers.
      I had this burning desire to understand how HTML5 would affect us both now and in the years to come.&lt;/p&gt;
      
      &lt;p&gt;So now, lets get back to reality and my day job. While I had grandiose visions of creating a kick ass book, I still had
      obligations and commitments to maintain for my employer, Red Hat. During this time I was involved with a new project,
      actually this was the second project I co-founded at JBoss -  we named it &lt;a href=&quot;http://aerogear.org/&quot;&gt;AeroGear&lt;/a&gt; and officially
      launched in February of 2012. AeroGear now employs some of the greatest developers of our time. It is truly an honor to
      say I was a part of this project and I will always admire and respect what the developers behind this project produce.&lt;/p&gt;
      
      &lt;p&gt;Not long after AeroGear was launched, and after I’d spent a few months researching and writing my book, I realised that
      I was out of touch with what developers were truly facing. It’s easy to write about what “you think” developers want and
      need. But it’s a completely different story when you’re in the trenches and in the real-world of day to day development
      activities. So, I gave up my 4+ year tenure at Red Hat and submitted my resignation. Trust me, this was not an easy thing
      to do. I had a really awesome job at Red Hat, I worked remote and the company fully supported me to evangelize whatever
      project I was working on. This means I got to work and travel all over the world, and work with the brightest developers
      in our industry. But, I wanted more on a personal level. Not just for my book, but because I had gotten way too comfortable
      with my day job. From what I’ve seen, as IT professionals, it hurts us to stay at a job longer than 4 or 5 years these days.
      imo unless you have some really nice golden handcuffs or are truly happy with your situation, depending on a company for retirement
      is suicide. So I took it upon myself to become uncomfortable and to get back out in the real world. The only way you can
      experience the problems and challenges developers face is to be one of them and work in their environment.&lt;/p&gt;
      
      &lt;p&gt;In March of 2012, I put in my 2 week notice at Red Hat and decided to become an independent consultant. I had interviewed
      at quite a few companies and decided the best route to take was the most uncomfortable one - a pair programming Ruby/UI developer.
      So I started a contract with a Cox owned property and experienced, first hand, the problems that professional developers face.
      Things like converting a six year old legacy B2B application from prototype.js to jQuery. Other front-end problems like
      jQuery architecture and writing plugins, strategies to bubble up DOM events, etc... CSS formatting, preprocessor strategies
      and many more issues that your average corporate developers desire to get right. I was finally in the trenches with an audience
      that “I thought” I previously understood.&lt;/p&gt;
      
      &lt;p&gt;In the weeks/months before my consulting time at Cox/Manheim I had been engaged by Square, Google and Wikipedia for potential jobs offers.
      So I was rushing home in the afternoons to interview for positions that would move me out to the bay area. Unfortunately these
      opportunities didn’t work out for whatever reason, but honestly, putting myself out there and going through these grueling
      interview processes helped me out tremendously - as you will see.&lt;/p&gt;
      
      &lt;p&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2012-11-01/543116336.jpg&quot; alt=&quot;devnexus&quot; class=&quot;margin10&quot; style=&quot;max-width:50%&quot; align=&quot;left&quot;&gt;
      On a side note and speaking of &quot;putting myself out there&quot;, on March 21st I had agreed to do a talk at a local conference
      here in Atlanta called &lt;a href=&quot;http://www.devnexus.com/&quot;&gt;DevNexus&lt;/a&gt;. As I was creating the slides for my presentation, I kept thinking
      about how I would verbally survey the audience at certain points to get a feel for what their experience level was.
      “Raise your hand if...” kind of thing...Then I thought, hey! I can just write a simple HTML+CSS slide deck and create a
      WebSocket back end that will allow the audience to participate with their mobile phone. Cool! So I spent a week hacking
      on this and finally got a prototype up and running.
      I did the talk and the room was packed, people were &lt;a href=&quot;http://wesleyhales.com/images/posts/2012-11-01/c70jx.jpg&quot;&gt;spilling out into the hallways&lt;/a&gt; (ok, so it wasn’t exactly a HUGE room,
      but still it’s fun to say) Anyway, The talk went great and I had almost 100% audience participation. I was invited back
      the next day to give the same talk after another speaker backed out.&lt;/p&gt;
      
      &lt;p&gt;Now that I was an independent contractor, I had this feeling of, yes, you guessed it... independence. I was getting paid Corp-2-Corp
      through whoever would hire me at a specified hourly rate. I was able to speak at conferences on organic, community topics and
      I wasn’t giving a sales pitch for a specific product or platform. I was a hired gun and making it on my own, paying high insurance
      costs for my family (and business), and making one hell of a commute.
      &lt;a href=&quot;http://www.flickr.com/photos/highgroove/6958058518/sizes/o/in/photostream/&quot;&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2012-11-01/onslyde.jpg&quot; alt=&quot;devnexus&quot; class=&quot;margin10&quot; align=&quot;right&quot; style=&quot;max-width:50%&quot;&gt;&lt;/a&gt;
      So, my next bright idea was to enter Atlanta Startup Weekend in April of 2012, form a team of volunteers and pitch the presentation
      tool that I used at DevNexus as a startup idea.
      Unfortunately, the idea didn’t get picked, but I met 3 awesome developers who joined my team and those connections were huge wins. I
      also made connections with many other like minded entrepreneurs, so overall my first time joining an event like this was priceless.
      Again, &lt;a href=&quot;https://twitter.com/mikeschinkel/status/194207658033680384&quot;&gt;just putting myself out there&lt;/a&gt; was another way to level up...&lt;/p&gt;
      
      &lt;p&gt;2 months into my contract at Cox (June), I was finally getting close to finishing my O’Reilly book. A lot of my effort was going
      into the code examples in the book and the ideas behind it. So in June, I finally launched &lt;a href=&quot;http://www.html5e.org&quot;&gt;html5e.org&lt;/a&gt;.
      This site contains a ton of examples and practical implementations of W3C and HTML5 apis. The basic idea behind html5e is to
      defragment the mobile (and desktop) browser space by using a core set of APIs. &lt;a href=&quot;http://www.html5e.org&quot;&gt;Read more here&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;After 3 months with my consulting gig at Cox/Manheim, I received a call from the senior development director at CNN. He
      had attended the same talk I gave at DevNexus 2012 (where I used my presentation tool), and wanted to know if I’d be
      interested in joing the CNN.com development team. I was pretty happy with my contract at Cox, but after I asked what I’d
      be working on, I couldn’t turn the offer down. He told me that I’d be working on the responsive re-design of CNN.com or
      improving overall performance. Who wouldn’t jump at the chance to improve a site that gets 60 million uniques per day?
      To say the least, I had been “primed” for interviews after my experiences with Square, Google, and Wikipedia so I felt
      completely comfortable walking into my interview at CNN. Onsite, I took a 30 minute written exam and interviewed with 7
      people. CNN does a great job of screening candidates. Luckily I made it through the screen and started the contract on
      July 1st.&lt;/p&gt;
      
      &lt;p&gt;At this point, just the interview practice alone had given me a great idea on the bar that the world’s top technology companies
      set. It’s invaluable and I recommend everyone do it, especially if you’re a cocky, egotistical developer type who thinks
      he/she is the hottest thing since Honey Boo-Boo :)&lt;/p&gt;
      
      &lt;p&gt;Not sure if you notice the pattern here, but somehow I managed to start jobs at the beginning of each quarter. No real
      importance behind it, just thought it’s cool that it continues to happen throughout the entire year.&lt;/p&gt;
      
      &lt;p&gt;While I was working at CNN, I immediately took the initiative
      to look at how they were implementing their “share bar” or buttons that allowed visitors to share content through social media.
      I also wanted to understand how Web Intents could possibly fit into the picture here.
      &lt;a href=&quot;http://wesleyhales.com/blog/2012/07/11/Sharing-With-Web-Intents-Today/&quot;&gt;My findings&lt;/a&gt; were interesting enough to get some of the top
      developers/authors/speakers in the industry to comment on my post. It really is motivating when you see your blog spike
      from roughly 100 unique visitors a week to 1000's. I even got a &lt;a href=&quot;https://twitter.com/TwitterOSS/status/240912782000795649&quot;&gt;shout out&lt;/a&gt; on TwitterOSS :)
      &lt;img src=&quot;http://localhost:4242/images/posts/2012-11-01/blogstats.png&quot; alt=&quot;devnexus&quot; class=&quot;margin10 max-width-100&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;Next thing I worked on at CNN was page load performance. We started having meetings with CNN’s best and brightest to see what
      we could do to add performance improvements to CNN’s home page. The problem with making changes like these in most large
      organizations is that everything is product based. Therefore, you usually don’t have any internal sponsorship (or funds) to
      make these kinds of changes. Fortunately for me, I was willing to take afternoons and downtime to work on the performance issues.
      After taking a look at what could be done, we decided to break JQuery out of the concatenation process and far-future cache
      it. That simple change alone Improved CNN.com performance by 17% and saved almost 1TB of outgoing data per day. You see,
      CNN does regular interval releases like most folks and their main concatenated JS file is revved on each release. So users
      had to re-download that file upon each visit after release.
      Before we made the change, we had to have a way to measure the performance impact both before and after improvements were
      made. Enter &lt;a href=&quot;http://phantomjs.org/&quot;&gt;PhantomJS&lt;/a&gt; - With phantomjs, we were able to create a script (later named &lt;a href=&quot;http://loadreport.wesleyhales.com/&quot;&gt;loadreport.js&lt;/a&gt;)
      that would run for each development build. Thus, giving us a baseline for the changes we were making. For the full story behind loadreport.js,
      check out &lt;a href=&quot;http://wesleyhales.com/blog/2012/08/16/Site-Load-Time-Testing-with-PhantomJS/&quot;&gt;this post&lt;/a&gt;.
      On August 16th, loadreport was picked up in the &lt;a href=&quot;http://javascriptweekly.com/archive/92.html&quot;&gt;JavaScript weekly newsletter&lt;/a&gt; and again, blog spikes were abundant :)&lt;/p&gt;
      
      &lt;p&gt;The point is, I don’t give a damn who you’re working for and what you’re doing; just blog about it. If you want to get better, write about it.
      Find something to write about if you’re working on boring shit.&lt;/p&gt;
      
      &lt;p&gt;My time at CNN was a lot of fun and I met some really talented developers. I had no intentions of leaving this job and planned
      on staying there for my full contract length, BUT.... one day I got a call. The call came from an good friend and colleague
      that I had previously helped to bootstrap a startup. I was actually the third co-founder of this startup, but I had to back out
      due to all the craziness that you just read about (and more). But I still had a vested interest in the company and we parted ways on good terms.
      So, I was told that they had just been &lt;a href=&quot;http://blog.apigee.com/apigee_acquires_instaops_embracing_the_apps_everywhere_world&quot;&gt;acquired&lt;/a&gt; by
      a startup in Palo Alto called &lt;a href=&quot;http://apigee.com&quot;&gt;Apigee&lt;/a&gt; and he wanted me to come pick up where I left off.
      On October 1, I started full time employment with Apigee and I couldn't be happier. I had the opportunity of taking &lt;a href=&quot;http://wesleyhales.com/design/?p=design&quot;&gt;my original UI&lt;/a&gt;
      and integrating it with Apigee’s &lt;a href=&quot;http://apigee.com/about/mobile-analytics&quot;&gt;look and feel&lt;/a&gt; amongst many other things. This has
      really been the icing on top - the cherries come in the following section - of an incredible 1 year journey. I'm looking forward to
      doing many great things with Apigee's technology and the future of the web applications.&lt;/p&gt;
      
      &lt;p&gt;Steve Jobs said it best in 2005, when he told those Stanford students to “Stay hungry. Stay foolish”. Even though I
      could stand to lose about 10-15 pounds. I have stayed foolish and I listened to my heart on what I should do. I constantly
      had butterflies in my stomach and was pushed to the very edge of the stress levels that I could handle. That is how I
      knew I was doing something worthwhile.&lt;/p&gt;
      
      &lt;p&gt;On October 26th, my O’Reilly book is done and was sent to the printer. It is now available as an &lt;a href=&quot;http://shop.oreilly.com/product/0636920024088.do&quot;&gt;ebook&lt;/a&gt;
      and will be available in print on November 12th.&lt;/p&gt;
      
      &lt;p&gt;On November 1st (today), the idea that I helped create and shape got it’s first &lt;a href=&quot;http://finance.yahoo.com/news/apigee-launches-first-real-time-120000461.html&quot;&gt;press release&lt;/a&gt;
      and &lt;a href=&quot;http://apigee.com/about/mobile-analytics&quot;&gt;official public launch&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;&lt;img src=&quot;http://localhost:4242/images/posts/2012-11-01/apigee.png&quot; alt=&quot;apigee mobile analytics&quot; class=&quot;margin10 max-width-100&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;I’ll be speaking at a few more conferences in November, &lt;a href=&quot;http://www.devoxx.com/display/DV12/Wesley+Hales&quot;&gt;Devoxx&lt;/a&gt;
      and &lt;a href=&quot;http://therichwebexperience.com/conference/speaker/wesley_hales&quot;&gt;RWX&lt;/a&gt;, and after that I’m going to lay low for a while.
      The amount of stress that I’ve undergone over the past year is not for the faint of heart. Imagine trying to prove yourself
      to a new team of developers and managers every 90 days. On top of that, they all knew that I authored a book, so some people
      expect you to shit rainbows at times. Managing expectations can be a bit tricky as well. So I have my acid reflux medicine now,
      I can sleep pretty well after a couple of beers, and I won’t have to pay for many more haircuts as my hair falls out at an even faster rate :)&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2012/08/16/Site-Load-Time-Testing-with-PhantomJS.html</id>
    <title>Web Performance Testing With PhantomJS</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2012-08-16T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2012/08/16/Site-Load-Time-Testing-with-PhantomJS.html" rel="alternate" type="text/html" />
    <category term="phantomjs"></category>
    <category term="web performance"></category>
    <category term="testing"></category>
    <summary>
      
      
      HTTP requests, heavy/unminified resources, and UI thread blocking should be on the mind of every front-end developer. These
      are just a few issues that can cause serious bottlenecks in page load times. Having a faster load time equals better search engine
      rankings, higher conversion rates, and an overall reduction in bandwidth costs.
      
      I recently took on the task of coming up with an accurate way to measure all the aforementioned things, in an effort to understand
      which performance tweaks improved page load times and which ones didn't. But first, we needed a baseline to test how fast the page loads with both a clear-cache...
    </summary>
    <content type="html">
      &lt;p&gt;&lt;img src=&quot;http://localhost:4242/images/icons/phantomjs.png&quot; alt=&quot;phantomjs&quot; align=&quot;left&quot; class=&quot;max-width-100 margin10&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;HTTP requests, heavy/unminified resources, and UI thread blocking should be on the mind of every front-end developer. These
      are just a few issues that can cause serious bottlenecks in page load times. Having a faster load time equals better search engine
      rankings, higher conversion rates, and an overall reduction in bandwidth costs.&lt;/p&gt;
      
      &lt;p&gt;I recently took on the task of coming up with an accurate way to measure all the aforementioned things, in an effort to understand
      which performance tweaks improved page load times and which ones didn't. But first, we needed a baseline to test how fast the page loads with both a clear-cache and primed-cache state; Enter PhantomJS.
      PhantomJS gives us a way to headlessly test page performance, and also gives us the automation we need for integration with any build system.
      For this article, I will explain the reporting tool I used and try to give you a starting point for testing your own site(s).&lt;/p&gt;
      
      &lt;p&gt;First off, I started with James Pierce's &lt;a href=&quot;https://github.com/jamesgpearce/confess/&quot;&gt;confess.js&lt;/a&gt; which gives us the elapsed load
      time of a web page, the slowest and fastest resources, along with many other cool things like automatic generation of an appcache manifest. However, it did not give us
      the document.readyState=interactive/complete or window.onload times. Another thing I wanted to measure was before and after cache. So If at first,
      we have resources which are not far-future cached, what happens after we future cache these things? Also, how fast does our page load after
       being cached?&lt;/p&gt;
      
      &lt;p&gt;With a few performance focused modifications to confess.js, we are able to gather the following results:&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;document.readyState&lt;/li&gt;
      &lt;li&gt;image filmstrip (how the page looks over load time)&lt;/li&gt;
      &lt;li&gt;page and resource load times after the user has a primed cache.&lt;/li&gt;
      &lt;li&gt;pretty effin cool charts with sparklines fed by knockout.js&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;This script is running live at &lt;a href=&quot;http://loadreport.wesleyhales.com/report.html&quot;&gt;loadreport.wesleyhales.com/report.html&lt;/a&gt;
      &lt;img src=&quot;http://localhost:4242/images/loadreport.js.png&quot; alt=&quot;loadreport.js&quot; align=&quot;left&quot; class=&quot;max-width-100&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;We're running the test 5 times in a row, to give an average of your best load times and to see where spikes occur. Also, &lt;a href=&quot;http://twitter.com/ryanbridges&quot;&gt;@ryanbridges&lt;/a&gt; put together
      some awesome sparkline charts backed by knockout.js. Just click on the &quot;Show Me Some Charts!&quot; button to see 'em.
      &lt;img src=&quot;http://localhost:4242/images/loadreport-charts.png&quot; alt=&quot;loadreport-charts&quot; align=&quot;left&quot; class=&quot;max-width-100 margin10&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;Regarding cache performance, phantomjs has a --disk-cahe=yes switch which is supposed to enable caching, but the results on the number
      of resources loaded and their size seem to be reversed. For example, if we run this script against cnn.com with --disk-cahe=yes, phantom returns
      over 2MB of resources, but if we run it with the same switch set to &quot;no&quot;, we get 858KB of resources - and both modes report the same number
      of resources being loaded (around 150).
      To bypass this bug, I've created my own caching mechanism which basically loads the same page twice (in the same phantom instance)
       and returns more accurate results when compared with Chrome's developer tools.&lt;/p&gt;
      
      &lt;p&gt;Install &lt;a href=&quot;http://phantomjs.org/&quot;&gt;phantomjs&lt;/a&gt; 1.6+, &lt;a href=&quot;https://github.com/wesleyhales/loadreport&quot;&gt;Get the script here&lt;/a&gt; and run this on your own build servers to make sure your UI screams.&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://twitter.com/wesleyhales&quot;&gt;@wesleyhales&lt;/a&gt;&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;br&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2012/07/19/HTML5-in-Atlanta.html</id>
    <title>HTML5 is Booming in Atlanta</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2012-07-19T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2012/07/19/HTML5-in-Atlanta.html" rel="alternate" type="text/html" />
    <category term="html5"></category>
    <category term="atlanta"></category>
    <summary>
      So, all I can say is that the Atlanta HTML5 community is awesome. Today the @atlhtml5 user group has reached it's 1000th member! From startups to companies in the Alexa top 20 rankings, Atlanta is heading towards a bright future in innovation and the open web. Front-end developers are in serious demand as Atlanta based companies strive to build web applications that are more offline accessible, responsive, and performant. Companies are moving more JavaScript to the browser, and this demands more structured code following MVC style patterns. Of course, the recent rise of JavaScript frameworks and many other modern browser...
    </summary>
    <content type="html">
      &lt;p&gt;&lt;img src=&quot;http://localhost:4242/images/icons/atlhtml5.jpg&quot; alt=&quot;atlanta html5&quot; align=&quot;left&quot; class=&quot;max-width-100 margin10&quot;&gt;So, all I can say is that the Atlanta HTML5 community is awesome. Today the &lt;a href=&quot;http://twitter.com/atlhtml5&quot;&gt;@atlhtml5&lt;/a&gt; user group has reached it's 1000th member! From startups to companies in the Alexa top 20 rankings, Atlanta is heading towards a bright future in innovation and the open web. Front-end developers are in serious demand as Atlanta based companies strive to build web applications that are more offline accessible, responsive, and performant. Companies are moving more JavaScript to the browser, and this demands more structured code following MVC style patterns. Of course, the recent rise of JavaScript frameworks and many other modern browser APIs don't fall under HTML5 directly, but they all showed up around the same time, along with the mobile web boom. This is why HTML5 is the #1 job trend on indeed.com and is the fastest growing keyword found in online job postings.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;div style=&quot;width:540px;margin: 0 auto&quot;&gt;
      &lt;a href=&quot;http://www.indeed.com/jobtrends&quot; title=&quot;HTML5 Job Trends&quot;&gt;
      &lt;img width=&quot;540&quot; height=&quot;300&quot; src=&quot;http://www.indeed.com/trendgraph/jobgraph.png?q=HTML5&quot; border=&quot;0&quot; alt=&quot;HTML5 Job Trends graph&quot;&gt;
      &lt;/a&gt;
      &lt;table width=&quot;100%&quot; cellpadding=&quot;6&quot; cellspacing=&quot;0&quot; border=&quot;0&quot; style=&quot;font-size:80%&quot;&gt;&lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;http://www.indeed.com/jobtrends&quot;&gt;HTML5 Job Trends&lt;/a&gt;&lt;/td&gt;
      &lt;td align=&quot;right&quot;&gt;&lt;a href=&quot;http://www.indeed.com/jobs?q=Html5&quot;&gt;Html5 jobs&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;&lt;/table&gt;
      &lt;/div&gt;
      
      
      &lt;p&gt;When I started this user group exactly 11 months ago, I wasn't sure how far it would grow and had no idea who would be the following month's speaker. When you start a group (or any venture for that matter) completely unaware of who will show up and who will continue to come, regardless of the subject's popularity, it's easy to become a little unsure of yourself. Luckily, I had awesome friends and supporters from day one who helped the group become what it is.&lt;/p&gt;
      
      &lt;p&gt;I'm a firm believer in open source and giving everything away. It all comes back to you in multiple ways in the end. On that note, this group will never charge for an event or sell out as a platform for selling a product or service. I have turned down many cash offers from quite a few promoters/sales people who wish to use this community for their benefit and not give anything back to it. However, we will accept sponsorship of any company that wishes to help us bring in bigger speakers or generally support the group for equipment and other costs.&lt;/p&gt;
      
      &lt;p&gt;So thanks to all who have supported the &lt;a href=&quot;http://www.meetup.com/AtlantaHTML5/&quot;&gt;Atlanta HTML5 User Group&lt;/a&gt;. I'm not sure what will happen when HTML6 comes out, but we will have to think of another clever name ;)&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://twitter.com/wesleyhales&quot;&gt;@wesleyhales&lt;/a&gt;&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;br&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2012/07/11/Sharing-With-Web-Intents-Today.html</id>
    <title>Sharing Content with Web Intents</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2012-07-11T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2012/07/11/Sharing-With-Web-Intents-Today.html" rel="alternate" type="text/html" />
    <category term="web intents"></category>
    <category term="html5"></category>
    <category term="share"></category>
    <category term="stats"></category>
    <summary>
      
      
      
      The Intent of Sharing
      
      
      If you employ share buttons on your site, then you might already be aware of the increased load that comes with trying
      to make your content social. Allowing users to take action on your specific content and "share" it is a common task.
      Much like linking HTML documents together, we are now linking apps together that are capable of
       pushing content to a receiving service via the user. This action or intent of "sharing" content across different apps
       has recently been identified in a W3C Editors Draft called Web Intents.
      
      I recently took a job working on CNN.com and I'm...
    </summary>
    <content type="html">
      &lt;br&gt;
      
      
      &lt;h3&gt;The Intent of Sharing&lt;/h3&gt;
      
      
      &lt;p&gt;If you employ share buttons on your site, then you might already be aware of the increased load that comes with trying
      to make your content social. Allowing users to take action on your specific content and &quot;share&quot; it is a common task.
      Much like linking HTML documents together, we are now linking apps together that are capable of
       pushing content to a receiving service via the user. This action or intent of &quot;sharing&quot; content across different apps
       has recently been identified in a &lt;a href=&quot;http://dvcs.w3.org/hg/web-intents/raw-file/tip/spec/Overview.html&quot;&gt;W3C Editors Draft called Web Intents&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;I recently took a job working on &lt;a href=&quot;http://cnn.com&quot;&gt;CNN.com&lt;/a&gt; and I'm sure you can imagine that the weight and performance of social sharing is pretty serious 'round these parts.
      So I will break down the current state of sharing as it exists today, then jump into an examination of Web Intents.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h3&gt;Why do we need Web Intents? &lt;/h3&gt;
      
      
      &lt;p&gt;In today's world of sharing we have limited options.
      (Note that the &quot;share&quot; intent is one of many. You can also edit, save, etc... but this article is focused on sharing)
      We are forced to pull a JavaScript file and load a share button dynamically for the user, or we can encode a query string that will
      be the input on a GET request to the provided share service.&lt;/p&gt;
      
      &lt;p&gt;For this example, I've taken the most widely used social networks as an example. Each is linked to a simple HTML page that only contains
      their specific resources to display a share button for the given service:&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;http://localhost:4242/_examples/shares/twitter/&quot;&gt;Twitter&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://localhost:4242/_examples/shares/google/&quot;&gt;Google+&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://localhost:4242/_examples/shares/fb/&quot;&gt;Facebook&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://localhost:4242/_examples/shares/linkedin/&quot;&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;First, I wanted a true measurement on all the resources and page load times without anything in the cache.
      So I cleared the browser cache and loaded a single test page (from the list above) for each share service provider. Here are the results:&lt;/p&gt;
      
      &lt;div id=&quot;container&quot; class=&quot;max-width-100&quot;&gt;&lt;/div&gt;
      
      
      &lt;p&gt;I know... seems pretty crazy that Facebook would have 11 HTTP requests and a 135KB payload (after compress/GZIP) for a share/like button.
      &lt;img src=&quot;http://localhost:4242/images/design/share-buttons/facebook.PNG&quot; alt=&quot;Facebook resources&quot; class=&quot;max-width-100 margin10&quot;&gt;
      LinkedIn is delivering 80KB of stuff, Twitter comes in right at 40KB, and although Google only serves up 2KB of resources, the data is broken up over 10 HTTP requests.&lt;/p&gt;
      
      &lt;p&gt;Keep in mind that we are on a desktop browser, so worrying about all the HTTP requests may be a little nonsensical. But, on a mobile
      browser this is definitely something you should be concerned about.
      The previous no-cache scenario is a unique, one time case for our users. And chances are, your user's browser may have already
      cached this content from another site using the same button resources.&lt;/p&gt;
      
      &lt;p&gt;So, after we load all the resources for the first time, surely those will be better cached via local/sessionStorage and
      optimized for fast load times and modern browsers, right? WRONG!&lt;/p&gt;
      
      &lt;p&gt;On page refresh we get the following results:&lt;/p&gt;
      
      &lt;div id=&quot;container2&quot; class=&quot;max-width-100&quot;&gt;&lt;/div&gt;
      
      
      &lt;p&gt;Here we see that there are no files being cached outside of the browsers default capabilities. Render times are still staying fairly consistent with the previous times, with the exception of Twitter, which
      was cut down to more than half of it's no-cache onload time.
      HTTP requests remain mostly the same, and sizes are a little better, but LinkedIn is still chiming in at 45KB... on each page load/refresh.&lt;/p&gt;
      
      &lt;p&gt;Lastly, when we click the share button for each provider, we get the following:&lt;/p&gt;
      
      &lt;div id=&quot;container3&quot; class=&quot;max-width-100&quot;&gt;&lt;/div&gt;
      
      
      &lt;p&gt;Ok, so we see something interesting here. Google is the only one who did lazy loading! \o/ Thanks Google! The additional 2KB
      of downloaded content creates the Google+ UI on the fly, but at a cost of 29 HTTP requests. Yes, that's right, 29.
      I didn't look very closely as to why LinkedIn updates the parent DOM, but your page has been abused pretty badly at
      this point so it probably doesn't matter too much :)&lt;/p&gt;
      
      &lt;p&gt;So with all of this data, we can clearly see that today's DIY sharing intents are raping our applications pretty hard. We have no idea what
      those resources are doing and they come at a high cost. Aside from the issues of resource weight, back doors, and inefficient architecture of sharing services, there are many other issues
       with the current ways we handle the sharing of data.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;h3&gt;Alternatives&lt;/h3&gt;
      
      
      &lt;p&gt;The best alternative that works across browsers today is a simple share URL. Throw in some kick ass, responsive &lt;a href=&quot;http://gregoryloucas.github.com/Font-Awesome-More/#all-icons&quot;&gt;font icons&lt;/a&gt;
       and we have a performant way to share content. But there are still a few problems with this approach:&lt;/p&gt;
      
      &lt;ol&gt;
      &lt;li&gt;We are faced with a potential list of
      social networks and options that our users may not even use or care about. We've all seen it before, it's the typical &quot;share bar&quot; found on most major
      news sites and blogs.&lt;/li&gt;
      &lt;li&gt;We don't have any way of receiving a callback on whether the post/share was successful or not. The only way to get this data is through async analytics
      by emedding a unique identifier in the URL. Then hope the referrer surfaces in next months usage reports.&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;p&gt;Here are the corresponding share URLs from the providers analyzed above.&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;
      &lt;a href=&quot;https://developer.linkedin.com/documents/share-linkedin&quot;&gt;LinkedIn:&lt;/a&gt; http://www.linkedin.com/shareArticle?mini=true&amp;amp;url={articleUrl}&amp;amp;title={articleTitle}&amp;amp;summary={articleSummary}&amp;amp;source={articleSource}&lt;/li&gt;
      &lt;li&gt;
      &lt;a href=&quot;https://dev.twitter.com/docs/intents&quot;&gt;Twitter:&lt;/a&gt; https://twitter.com/intent/tweet?url={articleURL} 
      &lt;/li&gt;
      &lt;li&gt;
      &lt;a href=&quot;https://dev.twitter.com/docs/intents&quot;&gt;Facebook:&lt;/a&gt; http://www.facebook.com/sharer.php?u={url to share}&amp;amp;t={title of content}&lt;/li&gt;
      &lt;li&gt;
      &lt;a href=&quot;https://dev.twitter.com/docs/intents&quot;&gt;Google+:&lt;/a&gt; https://plus.google.com/share?url={articleURL}&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;br&gt;
      
      
      &lt;h3&gt;Web Intents&lt;/h3&gt;
      
      
      &lt;p&gt;If you're still struggling to wrap your head around Web Intents, you're not alone. I had to sit down and run through the latest &lt;a href=&quot;http://intentlab-io12.appspot.com/&quot;&gt;Google IO 2012 code exercises&lt;/a&gt;, &lt;a href=&quot;http://www.youtube.com/watch?v=O1YjdKh-rPg&amp;amp;feature=player_embedded#!&quot;&gt;videos&lt;/a&gt;, and &lt;a href=&quot;http://www.smartjava.org/content/html5-web-intents-share-information-between-web-apps&quot;&gt;articles&lt;/a&gt; on Web Intents to really see how it is currently implemented and what it takes to make it work. As of this writing, the only
      browser supporting the &lt;code&gt;WebKitIntent&lt;/code&gt; api is, you guessed it, WebKit. This includes Chrome versions &amp;gt;= 19. But, even though the tag is supported, you must install
      a Chrome extension to actually fulfill the intent.&lt;/p&gt;
      
      &lt;p&gt;Here we see what happens when I click a Web Intent enabled button for sharing an image. You can try it out &lt;a href=&quot;http://localhost:4242/_examples/shares/intent/&quot;&gt;here&lt;/a&gt;.
      &lt;img src=&quot;http://localhost:4242/images/design/webintent-pick.PNG&quot; alt=&quot;web intent pick&quot; class=&quot;max-width-100 margin10&quot;&gt;&lt;/p&gt;
      
      &lt;p&gt;At this point you are probably wondering: How do we get the dialogue to show up in teh browser? How can we register an application to handle this request?
      The plan is to allow web applications to register themselves through a provided JavaScript api or HTML tag when the specification is
      final. For now, we must use a Chrome extension.&lt;/p&gt;
      
      &lt;p&gt;This is a section pulled from the manifest file in the extension I'm using.&lt;/p&gt;
      
      &lt;div class=&quot;full-width clear&quot;&gt;
      &lt;code&gt;
      &lt;pre&gt;
      &quot;intents&quot;: {
            &quot;http://webintents.org/save&quot; : {
            &quot;type&quot;: [&quot;image/jpg&quot;, &quot;image/jpeg&quot;, &quot;image/png&quot;, &quot;image/gif&quot;],
            &quot;title&quot;: &quot;PicStore&quot;,
            &quot;path&quot;: &quot;save.html&quot;,
            &quot;disposition&quot;: &quot;inline&quot;
          },
      &lt;/pre&gt;&lt;/code&gt;
      &lt;/div&gt;
      
      
      &lt;p&gt;To put it simply, this is how you register an application (Chrome extension) to be used as a Web Intent today. By using the namespace
      defined on the first line &quot;http://webintents.org/save&quot;, we can assign our intent to be handled by any app who has this namespace and accepts the supplied &quot;type&quot;.
      The &quot;path&quot; is just another HTML file which is included in my extension and the code on that page will handle the intent.&lt;/p&gt;
      
      &lt;p&gt;In our client application, where the intent originates from, we call the following code onclick to allow the user to choose an application
      to fulfill this intent.&lt;/p&gt;
      
      &lt;div class=&quot;full-width clear&quot;&gt;
      &lt;code&gt;&lt;pre&gt;
      function invoke() {
          var intent = new WebKitIntent({
              &quot;action&quot;:&quot;http://webintents.org/save&quot;,
              &quot;type&quot;:&quot;image/*&quot;,
              &quot;suggestions&quot;:[&quot;http://webintents.org/save&quot;,&quot;http://webintents.org/pick&quot;],
              &quot;data&quot;:location.href});
      
          var onSuccess = function(data) { alert(data) };
          var onError = function(data) { alert(data) };
      
          window.navigator.webkitStartActivity(intent, onSuccess, onError);
      }
      &lt;/pre&gt;&lt;/code&gt;
      &lt;/div&gt;
      
      
      &lt;p&gt;Web Intents are a really good solution to the problems I mentioned in the first part of this article. I'm sure there are many kinks
      which will be ironed out in upcoming revisions to the spec, but overall it seems like a nice fit as we transition to the &quot;browser as a platform&quot;
      and find new ways of linking data and applications.
      As I said earlier, the plan is to allow any web application to register itself in the browser/UserAgent and I'm assuming some kind of user approval will go along with that.
      The proposed way of registering an application is with the &lt;code&gt;&amp;lt;intent&amp;gt;&lt;/code&gt; tag:
      &lt;code&gt;&lt;pre&gt;
      &amp;lt;intent
        action=&quot;http://webintents.org/share&quot;
        type=&quot;image/*&quot;
        href=&quot;share.html&quot;
        disposition=&quot;window|inline&quot;
       /&amp;gt;
      &lt;/pre&gt;&lt;/code&gt;
      Until this is implemented across browsers, all we have is the Chrome Web Store and extensions to take advantage of this technology.
      Read more about the details of Web Intents &lt;a href=&quot;http://webintents.org&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;*Note - Twitter has made the best attempt at an early implementation of Web Intents. The best thing service providers can do today, is follow &lt;a href=&quot;https://dev.twitter.com/docs/intents&quot;&gt;Twitter's implementation&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;For a full example on how to create a Web Intent Chrome extension, run through the examples in &lt;a href=&quot;http://intentlab-io12.appspot.com/&quot;&gt;this Google IO lab at #IO12&lt;/a&gt;.
      Or you can try it out with Chrome 19+ and the simple demo I wrote &lt;a href=&quot;http://localhost:4242/_examples/shares/intent/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;br&gt;
      
      
      &lt;h3&gt;Other references and good reads:&lt;/h3&gt;
      
      
      &lt;p&gt;&lt;a href=&quot;http://benlog.com/articles/2012/02/09/a-simpler-webbier-approach-to-web-intents-or-activities/&quot;&gt;Web Activities&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://tantek.com/2011/220/b1/web-actions-a-new-building-block&quot;&gt;Web Actions&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://www.smartjava.org/content/html5-web-intents-share-information-between-web-apps&quot;&gt;Dev article&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;https://plus.google.com/116171619992010691739/posts&quot;&gt;+WebIntents&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=O1YjdKh-rPg&amp;amp;feature=player_embedded#!&quot;&gt;Intro video from Google IO 2012&lt;/a&gt;&lt;/p&gt;
      
      &lt;br&gt;
      
      
      &lt;br&gt;
      
      
      &lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js&quot; type=&quot;text/javascript&quot; defer&gt;&lt;/script&gt;
      
      
      &lt;script src=&quot;http://code.highcharts.com/highcharts.js&quot; defer&gt;&lt;/script&gt;
      
      
      &lt;script src=&quot;http://code.highcharts.com/modules/exporting.js&quot; defer&gt;&lt;/script&gt;
      
      
      &lt;script src=&quot;/js/sharing-web-intents-charts.js&quot; defer&gt;&lt;/script&gt;
    </content>
  </entry>
  <entry>
    <id>http://localhost:4242/blog/2012/06/08/Sniffing-IE9-while-in-compatibility-mode.html</id>
    <title>Sniffing IE9 features while in compatibility mode</title>
    <updated>2015-10-27T10:57:22-04:00</updated>
    <published>2012-06-08T00:00:00+00:00</published>
    <link href="http://localhost:4242/blog/2012/06/08/Sniffing-IE9-while-in-compatibility-mode.html" rel="alternate" type="text/html" />
    <category term="ie"></category>
    <category term="features"></category>
    <category term="sniffing"></category>
    <summary>
      Getting the browser version from the User Agent string is one thing. But, when you
      force compatibility mode in IE, you get whatever version you're forcing to. e.g...
      &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=EmulateIE8&quot;/&gt;
      
      in IE9 will cause jQuery's
      
      ($.browser.version, 10)
      
      to return "8" :(
      
      I started digging through some msdn docs to find various
      ways of sniffing the actual browser we're using, even when compatibility mode is forced. This led me to this doc
      Which talks about how IE9's Chakra JavaScript engine processes math precision differently (and faster) than the old IE8 JScript engine.
      
      So using the following bit of code, we are able to detect the true browser version no...
    </summary>
    <content type="html">
      &lt;p&gt;Getting the browser version from the User Agent string is one thing. But, when you
      force compatibility mode in IE, you get whatever version you're forcing to. e.g...
      &lt;code&gt;&lt;pre&gt;&amp;lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=EmulateIE8&quot;/&amp;gt;&lt;/pre&gt;
      &lt;code&gt;&lt;/code&gt;&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;in IE9 will cause jQuery's&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;&lt;pre&gt;($.browser.version, 10)&lt;/pre&gt;&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;to return &quot;8&quot; :(&lt;/p&gt;
      
      &lt;p&gt;I started digging through some &lt;a href=&quot;http://blogs.msdn.com/b/ie/archive/2011/03/24/ie9-s-document-modes-and-javascript.aspx&quot;&gt;msdn docs&lt;/a&gt; to find various
      ways of sniffing the actual browser we're using, even when compatibility mode is forced. This led me to &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ie/gg622938.aspx&quot;&gt;this doc&lt;/a&gt;
      Which talks about how IE9's Chakra JavaScript engine processes math precision differently (and faster) than the old IE8 JScript engine.&lt;/p&gt;
      
      &lt;p&gt;So using the following bit of code, we are able to detect the true browser version no matter what compatibility mode it's in.
      &lt;code&gt;&lt;pre&gt;
      if ($.browser.msie &amp;amp;&amp;amp; parseInt($.browser.version, 10) &amp;lt;= 8) {
      var x = 6.28318530717958620000;
      var val = Math.sin(x);
        if(Math.abs(val) === 2.4492127076447545e-16){
        //do your IE6,7,8 shit here
        }
      &lt;/pre&gt;&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;Easier/better way?&lt;/p&gt;
    </content>
  </entry>
</feed>
