<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 <title>Revelation Labs</title>
 <link href="http://labs.revelationglobal.com/atom.xml" rel="self"/>
 <link href="http://labs.revelationglobal.com/"/>
 <updated>2011-10-07T14:55:44-07:00</updated>
 <id>http://labs.revelationglobal.com/</id>
 <author>
   <name></name>
 </author>
 
 
 <entry>
   <title>scrollHeight, scrollTop, and outerHeight: Making sense of JavaScript scrolling geometry with JQuery</title>
   <link href="http://labs.revelationglobal.com/2010/02/04/javascript_scrolling_geometry.html"/>
   <updated>2010-02-04T00:00:00-08:00</updated>
   <id>http://labs.revelationglobal.com/2010/02/04/javascript_scrolling_geometry</id>
   <content type="html">&lt;h2&gt;Intro&lt;/h2&gt;
&lt;p&gt;This article is written for those who find themselves working on two problems:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Getting information about the scrolling state of an html element.&lt;/li&gt;
	&lt;li&gt;Using JavaScript to do so.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your main foe here is history, as years and years of cruft and backwards compatibility support have all been patiently building up to the tangle that is this moment. Your enemies have gathered, and they will take great strength to overcome.&lt;/p&gt;
&lt;p&gt;My methods will require JQuery (1.4 is the current release, but this should apply to many versions). Take a moment to go get it and include it in your project.&lt;/p&gt;
&lt;h2&gt;Info&lt;/h2&gt;
&lt;p&gt;To conquer scrolling, learn the difference between these three different scroll state values (see illustration below):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;element.scrollHeight&lt;/strong&gt;: &lt;br /&gt;
        a plain javascript attribute, note the lack of parenthesis. The entire scrollable height of the element (in pixels, floating point)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;JQuery.outerHeight()&lt;/strong&gt;: &lt;br /&gt;
        JQuery method of a scrollable element. The height of the visible portion of the scrollable element (in pixels, floating point)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;JQuery.scrollTop()&lt;/strong&gt;:&lt;br /&gt;
        JQuery method of a scrollable element. The height of the invisible portion of the element above the current scrolled area. Effectively, this is the offset of the scrollbar from top. (in pixels, floating point)&lt;br /&gt;
bq.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/scroll_explained.png&quot; title=&quot;Scrolling Explained!&quot; alt=&quot;Scrolling Explained!&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Examples &amp;#8230;&lt;/h2&gt;
&lt;script src=&quot;http://gist.github.com/295372.js&quot;&gt;&lt;/script&gt;</content>
 </entry>
 
 <entry>
   <title>Unicorn, I18n and it's Thread</title>
   <link href="http://labs.revelationglobal.com/2009/11/13/unicorn_and_i18n.html"/>
   <updated>2009-11-13T00:00:00-08:00</updated>
   <id>http://labs.revelationglobal.com/2009/11/13/unicorn_and_i18n</id>
   <content type="html">&lt;p&gt;We&amp;#8217;re in the process of switching over to Unicorn here at Revelation and yesterday we started to notice some strange behavior with I18n. The I18n locale we set in a previous request was persisting to the next. Digging into I18n we found out why: I18n holds the current locale on a thread-local variable, and unicorn does not start a new thread for each new request, so the current locale or any other thread-local variable will persist across requests. Here&amp;#8217;s a quick example to show the different behavior of Mongrel vs. Unicorn with thread-local variables.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a really basic Sinatra app:&lt;/p&gt;
&lt;script src=&quot;http://gist.github.com/233679.js&quot;&gt;&lt;/script&gt;&lt;p&gt;If we start this app up with Mongrel and go to /portland we get: &amp;quot;Portland: &amp;quot;. The value of our thread-local variable is nil, because mongrel creates a new thread for each request.&lt;/p&gt;
&lt;p&gt;If we start this app up with Unicorn and go to /portland we get: &amp;#8220;Portland: is awesome&amp;#8221;. Unicorn has kept the same thread across both requests so the thread-local variable is still set to &amp;#8220;is awesome&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Since I18n stores locale in a thread-locale variable you have to be very cautious to reset locale for each request or the last requests locale will persist and your users will get some strange behavior.&lt;/p&gt;
&lt;p&gt;Cheers,&lt;/p&gt;
&lt;p&gt;James&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Mongrel vs. Passenger vs. Unicorn</title>
   <link href="http://labs.revelationglobal.com/2009/10/06/mongrel_passenger_unicorn.html"/>
   <updated>2009-10-06T00:00:00-07:00</updated>
   <id>http://labs.revelationglobal.com/2009/10/06/mongrel_passenger_unicorn</id>
   <content type="html">&lt;p&gt;A quick word of caution before reading: everyone should do their own performance testing. Depending on your system/your stack/your code your result my vary.&lt;/p&gt;
&lt;p&gt;We tested mongrel, passenger and the new kid on the block: unicorn. Our goal in testing wasn&amp;#8217;t to test a simple rack or rails app. Our app is complex. We wanted to see what each of these servers could do with a very complicated action in our app.  One that has before_filters, nested partials, big sql lookups, and so on. We also wanted to test this in an environment that was as close to our production stack as possible. So all of our testing was against our staging server, under ssl with a full stack and a copy of our production database.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s our setup:&lt;br /&gt;
  Linux version 2.6.22-xen (Gentoo 4.1.2 p1.0.2)&lt;br /&gt;
  1 2.5ghz dedicated xen virtual &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt;&lt;br /&gt;
  768MB memory&lt;br /&gt;
  For each test we booted up 3 workers of each server.&lt;/p&gt;
&lt;p&gt;We used &lt;a href=&quot;http://www.joedog.org/index/siege-home&quot;&gt;siege&lt;/a&gt; to test each of the server candidates. The actual command looked something like this:&lt;/p&gt;
&lt;script src=&quot;http://gist.github.com/203534.js&quot;&gt;&lt;/script&gt;&lt;p&gt;The results were surprising. Below is a graph of the average response times for each server. As you can see passenger and mongrel are &lt;em&gt;almost&lt;/em&gt; identical. Both have a slope of around 1 second per 5 concurrent requests. Which means for a given second, each 5 concurrent requests you add will make the average response time of all requests go up by a full second. Unicorn on the other hand destroyed each an every request sent to it. It has a slope close to 1 second per 14 concurrent requests! Crazzzy fassssttttt.&lt;/p&gt;
&lt;p&gt;&lt;img style='width:607px' src='/images/unicorn/average_response.png'/&gt;&lt;/p&gt;
&lt;p&gt;We also measured the max response time (the longest response) for each test. The results are also on unicorn&amp;#8217;s side. After around 9 concurrent requests, passenger shoots through the roof. Having response times around &lt;strong&gt;16&lt;/strong&gt; seconds! Mongrel isn&amp;#8217;t as bad, but still got response times around 8 seconds once you get into the double digits of concurrent requests. Unicorn is flat. 2.17 seconds is maximum time it ever took to complete the request.&lt;/p&gt;
&lt;p&gt;&lt;img style='width:607px' src='/images/unicorn/max_response.png'/&gt;&lt;/p&gt;
&lt;p&gt;We aren&amp;#8217;t going to be jumping to unicorn in the near future. &lt;del&gt;Still a couple bugs to knock out&lt;/del&gt;. Our configuration still needs a little work. We don&amp;#8217;t have a monit recipe to monitor the unicorn workers, and our nginx configuration needs some work. But we thought the results were interesting. If you&amp;#8217;ve run some performance tests on your system we&amp;#8217;d love to hear about them. Please email us at labs@revelationglobal.com.&lt;/p&gt;
&lt;p&gt;Cheers,&lt;/p&gt;
&lt;p&gt;James&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>YUI uploader testing with Blue-ridge</title>
   <link href="http://labs.revelationglobal.com/2009/08/17/javascript_testing.html"/>
   <updated>2009-08-17T00:00:00-07:00</updated>
   <id>http://labs.revelationglobal.com/2009/08/17/javascript_testing</id>
   <content type="html">&lt;p&gt;The Revelation development team has been working hard to bring video uploading and encoding to Revelation. Whenever we do anything around here we always think &amp;#8216;&lt;span class=&quot;caps&quot;&gt;TEST&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;TEST&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;TEST&lt;/span&gt;&amp;#8217;! We decided to use YUI&amp;#8217;s uploader, which means that much of our uploading functionality was going to be in JavaScript. In the past we&amp;#8217;ve toyed around with tools like Screw-Unit or just basic Selenium tests to make sure our JavaScript is tested. For video uploading, however, we really needed to find robust full-featured and CI compatible JavaScript testing framework. We landed on &lt;a target='_blank' href=&quot;http://github.com/relevance/blue-ridge/tree/master&quot;&gt;Blue-ridge&lt;/a&gt;. The best thing about Blue-ridge is you can do some pretty powerful JavaScript testing without a browser. Blue-ridge achieves this feat by running in Rhino. &lt;a target='_blank' href=&quot;http://www.mozilla.org/rhino/&quot;&gt;Rhino&lt;/a&gt; is a Java-based JavaScript interpreter written by the guys over at Mozilla. Rhino is capable of rendering a full &lt;span class=&quot;caps&quot;&gt;DOM&lt;/span&gt; implementation that runs completely in JavaScript by loading a special version of Env.js, which results in a pure JavaScript browser. Pretty crazy!&lt;/p&gt;
&lt;p&gt;To fully test our new video uploader we needed to test private functions that were being called by a listener. This added another level of complexity. To get around this we pulled all the functionality of the methods called by the listener into our own custom name spaced object. The only functionality that we left in the methods directly called by the listener was to call the new methods in our custom name spaced object. This allowed us to have the maximum level of testability of our custom functionality and left the methods that the listener called as a bridge between the private functions and our custom object. I think this is best explained by looking at some code:&lt;/p&gt;
&lt;script src=&quot;http://gist.github.com/167993.js&quot;&gt;&lt;/script&gt;&lt;p&gt;In this example we&amp;#8217;re using YUI&amp;#8217;s uploader for video and a JQuery plugin we wrote to create a video uploader. That video upload will call &amp;#8216;onUploadError(event)&amp;#8217; if the uploader has an error. That method in turn calls &amp;#8216;display_error&amp;#8217; under the &amp;#8216;Revelation.video&amp;#8217; name space. This allows us to easily test the functionality of displaying an error and leave the event calling to the &lt;span class=&quot;caps&quot;&gt;YUI&lt;/span&gt; uploader. Below a simple test to make sure &amp;#8216;display_video&amp;#8217; acts correctly.&lt;/p&gt;
&lt;script src=&quot;http://gist.github.com/168091.js&quot;&gt;&lt;/script&gt;&lt;p&gt;This is a very simplified example but shows how to test something that otherwise is very hard to test. Because of Blue-ridge the test can run under our CI server so we always know this functionality is working fine.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Everything you never wanted to know about nginx</title>
   <link href="http://labs.revelationglobal.com/2009/07/31/nginx.html"/>
   <updated>2009-07-31T00:00:00-07:00</updated>
   <id>http://labs.revelationglobal.com/2009/07/31/nginx</id>
   <content type="html">&lt;p&gt;This is the end of a very long week indeed.  We&amp;#8217;ve been working hard adding video to our application, and learned quite a few things about Javascript&amp;#8217;s foibles and other equally impossible things to do with nginx.&lt;/p&gt;
&lt;p&gt;First off, tracking upload_progress with more than one nginx server in a load balanced environment.  The moral that we have from our story is: don&amp;#8217;t try this at work.  We had a problem where the initial upload would be uploading to one of our nginx servers, and then subsequent requests to other nginx servers for upload_progress would fail, because they weren&amp;#8217;t being buffered there.  You can do things with good load balancers and &amp;#8216;sticky&amp;#8217; sessions, but in our experience, it&amp;#8217;s just a bad idea altogether.&lt;/p&gt;
&lt;p&gt;Next: trying to turn off buffered uploads.  We were attempting to get nginx to act as a straight &lt;span class=&quot;caps&quot;&gt;TCP&lt;/span&gt; proxy to a remote nginx server that would handle uploads and track their status with the upload progress module to get around the problem we just described. This doesn&amp;#8217;t work.  As of this moment, there doesn&amp;#8217;t seem to be a way to configure nginx to not buffer an upload.&lt;/p&gt;
&lt;p&gt;It just turns out that this is a bad idea altogether.  We decided at last to have the client measure the state of their own uploads with the &lt;a href=&quot;http://developer.yahoo.com/yui/uploader/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;YUI&lt;/span&gt; flash uploader widget&lt;/a&gt;.  If you don&amp;#8217;t care for the flash requirement and don&amp;#8217;t care about upload progress, I can also recommend that you try the &lt;a href=&quot;http://developer.yahoo.com/yui/connection/&quot;&gt;Yahoo connection manager&lt;/a&gt; for asynchronous uploads.  We&amp;#8217;ve used it with great success here.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Welcome to Revelation Labs!</title>
   <link href="http://labs.revelationglobal.com/2009/07/06/welcome_to_revelation_labs.html"/>
   <updated>2009-07-06T00:00:00-07:00</updated>
   <id>http://labs.revelationglobal.com/2009/07/06/welcome_to_revelation_labs</id>
   <content type="html">&lt;p&gt;First, let me introduce the development and design culture we&amp;#8217;ve started here at &lt;a href=&quot;http://www.revelationglobal.com&quot;&gt;Revelation&lt;/a&gt;.  We practice &lt;a href=&quot;http://en.wikipedia.org/wiki/Extreme_Programming&quot;&gt;eXtreme Programming&lt;/a&gt; or XP.  We believe in short iterations and continually delivering business value in the form of working software.  We believe in testing, or more specifically, in writing tests &lt;a href=&quot;http://behaviour-driven.org/&quot;&gt;first&lt;/a&gt;. We believe in the tremendous value that interaction design brings to a product.&lt;/p&gt;
&lt;p&gt;In short, we are very proud of our work, our process, and our people, and the community that has inspired us.&lt;/p&gt;
&lt;p&gt;This is our effort to share what we have learned, and to contribute back to the larger community of developers and thinkers that make our work an expression of the joy of creation.&lt;/p&gt;</content>
 </entry>
 
</feed>
