SlideShare a Scribd company logo
1 of 77
Page Caching Resurrected:

                   Ben Sco eld – Viget Labs




Sunday, March 22, 2009
Page Caching Resurrected:
                   A Fairy Tale
                   Ben Sco eld – Viget Labs




Sunday, March 22, 2009
I’m a Rails guy


Sunday, March 22, 2009
and this is a Rails talk


Sunday, March 22, 2009
but this isn’t just for Rails


Sunday, March 22, 2009
the story


Sunday, March 22, 2009
Sunday, March 22, 2009
page caching



Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
class PigsController
                 caches_page :show

                   def show
                    @pig = Pig.find(params[:id])
                   end

                   def update
                    @pig = Pig.find(params[:id])
                    @pig.update_attributes(params[:pig])

                  expire_page :action => :show
                 end
                end




Sunday, March 22, 2009
Standard        1




                Page     3000




                                requests per second




Sunday, March 22, 2009
public

                         dynamic
                         content

Sunday, March 22, 2009
action caching


Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
class PigsController
                 require_login :show
                 caches_action :show

                   def show
                    @pig = Pig.find(params[:id])
                   end

                   def update
                    @pig = Pig.find(params[:id])
                    @pig.update_attributes(params[:pig])

                  expire_action :action => :show
                 end
                end




Sunday, March 22, 2009
Standard        1



              Action     500



                Page     3000




                                requests per second




Sunday, March 22, 2009
dynamic
                         content


Sunday, March 22, 2009
fragment caching

Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
<% cache(:key => 'index:piglist') do %>
                 <ul id=quot;pig-listquot;>
                  <% @pigs.each do |pig| %>
                   <li>
                     <%= image_tag pig.house.photo %>
                     <%= h pig.name %>
                   </li>
                  <% end %>
                 </ul>
                <% end %>




Sunday, March 22, 2009
class PigsController
                 # ...

                   def update
                    @pig = Pig.find(params[:id])
                    @pig.update_attributes(params[:pig])

                  expire_fragment :key => 'index:piglist'
                 end
                end




Sunday, March 22, 2009
Standard        1


         Fragment        20


              Action     500


                Page     3000




                                requests per second




Sunday, March 22, 2009
efficiency


Sunday, March 22, 2009
the idea


Sunday, March 22, 2009
Rails 2.3

Sunday, March 22, 2009
hello, metal


Sunday, March 22, 2009
class BigBadWolf
                 def self.call(env)
                   if env[quot;PATH_INFOquot;] =~ /^/threaten/
                     [
                       200,
                       {quot;Content-Typequot; => quot;text/htmlquot;},
                       quot;Little pig, little pig, let me in!quot;
                     ]
                   else
                     [
                       404,
                       {quot;Content-Typequot; => quot;text/htmlquot;},
                       quot;Not Foundquot;
                     ]
                   end
                 end
                end




Sunday, March 22, 2009
high-performance endpoints


Sunday, March 22, 2009
AJAX


Sunday, March 22, 2009
so...


Sunday, March 22, 2009
javascript

Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
<script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/
     Event.observe(window, quot;loadquot;, function() {
       Behaviors.onLoad();
       Behaviors.setLoggedIn();
       Login.setup();
       if ($(quot;loginquot;) && $(quot;login-formquot;)) {
         Event.observe('login', 'keydown', function(ev) {
           if (ev.keyCode == 13) { Login.submit(); }
         });
       }
     });
     Login.auth = function(login, password) {
       document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ...
       document.cookie = 'password=' + password + '; path=/account/authenticate; ...
       el = $$('body').first();
       if (el) {
         var script = document.createElement('script');
         script.type = 'text/javascript';
         script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ...
         el.appendChild(script);
       }
     }
    /*]]>*/</script>




Sunday, March 22, 2009
<ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;>
     <li id=quot;welcome-usernamequot; class=quot;firstquot;>
      Welcome
     </li>

      <li>
       <a href=quot;/profilequot; class=quot;utility-linkquot;>Profile</a>
      </li>

      <li>
       <a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;>Queue</a>
      </li>

     <li class=quot;sign-out-linkquot;>
      <a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;>Sign Out</a>
     </li>
    </ul>

    <ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot;>
     <li class=quot;first sign-out-linkquot;>
      <a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot;
         onclick=quot;Login.show($('top-login-form')); return false;quot;>Login</a>
     </li>
     <li class=quot;signin-border-leftquot;>
      <a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;>Forgot Password?</a>
     </li>
     <li class=quot;signin-border-leftquot;>
      <a href=quot;/signupquot; class=quot;utility-linkquot;>Sign Up</a>
     </li>
    </ul>




Sunday, March 22, 2009
<noscript>
     <ul class=quot;nojs usernavquot;>
      <li>
       Please <a href=quot;/support/quot;>enable javascript</a> to log in.
      </li>
     </ul>
    </noscript>

    <div id=quot;top-login-formquot; class=quot;usernav login-formquot; style=quot;display:nonequot;>
     <form action=quot;https://secure.hulu.com/account/authenticatequot;
       method=quot;getquot; name=quot;login-formquot; onsubmit=quot;Login.submit(this); return false;quot;>
      <span class=quot;login-statusquot;></span>
      <input id=quot;loginquot; class=quot;active loginquot; type=quot;textquot;
       style=quot;display: none;quot; name=quot;usernamequot;/>
      <input id=quot;passwordquot; class=quot;active passwordquot; type=quot;passwordquot;
       style=quot;display: none;quot; name=quot;passwordquot;/>
      <input class=quot;inactive dummy loginquot; type=quot;textquot; value=quot;usernamequot;
       name=quot;dummy_loginquot; />
      <input class=quot;inactive dummyquot; type=quot;textquot; value=quot;passwordquot; name=quot;dummy_passwordquot; />
      <input alt=quot;Loginquot; class=quot;login-submitquot;
       src=quot;http://static.hulu.com/images/btn-signin-small.gif?1237361096quot;
       style=quot;width: 39px; height: 20;quot; type=quot;imagequot; />
      <a href=quot;#quot;><img alt=quot;Cancelquot; border=quot;0quot; class=quot;hover-mequot; height=quot;20quot;
       id=quot;btn-x.gif123741536309506quot; onclick=quot;Login.cancel();return falsequot;
       src=quot;http://static.hulu.com/images/btn-x.gif?1237361096quot; width=quot;18quot; /></a>
     </form>

     <a href=quot;/signupquot; class=quot;utility-linkquot;>Sign Up</a>
    </div>




Sunday, March 22, 2009
<ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;>
     <li id=quot;welcome-usernamequot; class=quot;firstquot;>
      Welcome
     </li>

      <li>
       <a href=quot;/profilequot; class=quot;utility-linkquot;>Profile</a>
      </li>

      <li>
       <a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;>Queue</a>
      </li>

     <li class=quot;sign-out-linkquot;>
      <a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;>Sign Out</a>
     </li>
    </ul>

    <ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot;>
     <li class=quot;first sign-out-linkquot;>
      <a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot;
         onclick=quot;Login.show($('top-login-form')); return false;quot;>Login</a>
     </li>
     <li class=quot;signin-border-leftquot;>
      <a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;>Forgot Password?</a>
     </li>
     <li class=quot;signin-border-leftquot;>
      <a href=quot;/signupquot; class=quot;utility-linkquot;>Sign Up</a>
     </li>
    </ul>




Sunday, March 22, 2009
Sunday, March 22, 2009
hulu is insane
                          don’t do it like they do




Sunday, March 22, 2009
<script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/
     Event.observe(window, quot;loadquot;, function() {
       Behaviors.onLoad();
       Behaviors.setLoggedIn();
       Login.setup();
       if ($(quot;loginquot;) && $(quot;login-formquot;)) {
         Event.observe('login', 'keydown', function(ev) {
           if (ev.keyCode == 13) { Login.submit(); }
         });
       }
     });
     Login.auth = function(login, password) {
       document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ...
       document.cookie = 'password=' + password + '; path=/account/authenticate; ...
       el = $$('body').first();
       if (el) {
         var script = document.createElement('script');
         script.type = 'text/javascript';
         script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ...
         el.appendChild(script);
       }
     }
    /*]]>*/</script>




Sunday, March 22, 2009
<script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/
     Event.observe(window, quot;loadquot;, function() {
       Behaviors.onLoad();
       Behaviors.setLoggedIn();
       Login.setup();
       if ($(quot;loginquot;) && $(quot;login-formquot;)) {
         Event.observe('login', 'keydown', function(ev) {
           if (ev.keyCode == 13) { Login.submit(); }
         });
       }
     });
     Login.auth = function(login, password) {
       document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ...
       document.cookie = 'password=' + password + '; path=/account/authenticate; ...
       el = $$('body').first();
       if (el) {
         var script = document.createElement('script');
         script.type = 'text/javascript';
         script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ...
         el.appendChild(script);
       }
     }
    /*]]>*/</script>




Sunday, March 22, 2009
the* right way


                               *a
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
the standard approach




Sunday, March 22, 2009
class ItemsController < ApplicationController
      def index
        @user = User.find_by_login(params[:user])
        @items = Item.released_on(params[:date])
      end
     end




Sunday, March 22, 2009
class Item < ActiveRecord::Base
      has_many :pulls, :dependent => :destroy

       named_scope :released_on, lambda { |date|
         date ||= Item.maximum(:released_on)
         {:conditions => {:released_on => date}, :order => 'name ASC'}
       }

      def pulled_by?(user)
       x = user.nil? ? false : !self.pulls.by_user(user.id).empty?
      end
     end




Sunday, March 22, 2009
<h1>Releases</h1>

     <ul>
      <% @items.each do |item| %>
       <% content_tag_for :li, item do %>
        <%= image_tag 'cover.png', :alt => h(item.name), :class => 'cover' %>
        <%= image_tag('badge.png', :alt => 'pulling',:class => 'badge')
           if item.pulled_by?(@user) %>
        <p><%= h item.name %></p>
       <% end %>
      <% end %>
     </ul>




Sunday, March 22, 2009
the hybrid approach




Sunday, March 22, 2009
class ItemsController < ApplicationController
      caches_page :index

      def index
       @items = Item.released_on(params[:date]).all
      end
     end




Sunday, March 22, 2009
require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless
      defined?(Rails)

     class PullList
      def self.call(env)
        if env[quot;PATH_INFOquot;] =~ /^/pulls/
          date = '2008-11-05'
          user = '1'
          [
            200,
           {quot;Content-Typequot; => quot;application/javascriptquot;},
           [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]]
        else
          [404, {quot;Content-Typequot; => quot;text/htmlquot;}, [quot;Not Foundquot;]]
        end
      end
     end




Sunday, March 22, 2009
class Pull < ActiveRecord::Base
      belongs_to :user
      belongs_to :item

      named_scope :by_user, lambda { |user_id|
        {:conditions => {:user_id => user_id}}
      }
      named_scope :for_date, lambda { |date|
        {:include => :item, :conditions => {:items => {:released_on => date}}}
      }
     end




Sunday, March 22, 2009
$(document).ready(function() {
       $.getJSON('/pulls', function(data) {
         $.each(data, function() {
           $('#item_'+this).addClass('pulled');
         });
       });
     });




Sunday, March 22, 2009
the payoff


Sunday, March 22, 2009
Sunday, March 22, 2009
standard


Sunday, March 22, 2009
hybrid


Sunday, March 22, 2009
Standard        0.617




              Hybrid     0.039 0.096




                                       content load time




Sunday, March 22, 2009
when to use it




Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
no shirt, no javascript, no service




Sunday, March 22, 2009
Thank You
      ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/speakers/44
Sunday, March 22, 2009

More Related Content

Similar to Page Caching Resurrected: A Fairy Tale

Page Caching Resurrected
Page Caching ResurrectedPage Caching Resurrected
Page Caching ResurrectedBen Scofield
 
Background Processing in Ruby on Rails
Background Processing in Ruby on RailsBackground Processing in Ruby on Rails
Background Processing in Ruby on Railsrobmack
 
Latinoware Rails 2009
Latinoware Rails 2009Latinoware Rails 2009
Latinoware Rails 2009Fabio Akita
 
An Introduction To jQuery
An Introduction To jQueryAn Introduction To jQuery
An Introduction To jQueryAndy Gibson
 
IT Depends: Custom vs Packaged Software
IT Depends: Custom vs Packaged SoftwareIT Depends: Custom vs Packaged Software
IT Depends: Custom vs Packaged Software★ Selcuk Atli
 
Ecossistema Rails Campus Party 09
Ecossistema Rails   Campus Party 09Ecossistema Rails   Campus Party 09
Ecossistema Rails Campus Party 09Fabio Akita
 
Hacking Movable Type Training - Day 2
Hacking Movable Type Training - Day 2Hacking Movable Type Training - Day 2
Hacking Movable Type Training - Day 2Byrne Reese
 
Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)Sam Livingston-Gray
 
Google Analytics and Sungard HE Luminis
Google Analytics and Sungard HE LuminisGoogle Analytics and Sungard HE Luminis
Google Analytics and Sungard HE LuminisDavid Simpson
 
Adventurous Merb
Adventurous MerbAdventurous Merb
Adventurous MerbMatt Todd
 
Semcomp de São Carlos
Semcomp de São CarlosSemcomp de São Carlos
Semcomp de São CarlosFabio Akita
 
Javascript: Ajax & DOM Manipulation v1.2
Javascript: Ajax & DOM Manipulation v1.2Javascript: Ajax & DOM Manipulation v1.2
Javascript: Ajax & DOM Manipulation v1.2borkweb
 
Front end performance (RailsWayCon 2009 short talk)
Front end performance (RailsWayCon 2009 short talk)Front end performance (RailsWayCon 2009 short talk)
Front end performance (RailsWayCon 2009 short talk)Ralph von der Heyden
 
シックス・アパート・フレームワーク
シックス・アパート・フレームワークシックス・アパート・フレームワーク
シックス・アパート・フレームワークTakatsugu Shigeta
 
Lightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClientLightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClientAdam Wiggins
 
Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On RailsWen-Tien Chang
 
jQuery Internals + Cool Stuff
jQuery Internals + Cool StuffjQuery Internals + Cool Stuff
jQuery Internals + Cool Stuffjeresig
 

Similar to Page Caching Resurrected: A Fairy Tale (20)

Page Caching Resurrected
Page Caching ResurrectedPage Caching Resurrected
Page Caching Resurrected
 
Background Processing in Ruby on Rails
Background Processing in Ruby on RailsBackground Processing in Ruby on Rails
Background Processing in Ruby on Rails
 
Enecomp 2009
Enecomp 2009Enecomp 2009
Enecomp 2009
 
Latinoware Rails 2009
Latinoware Rails 2009Latinoware Rails 2009
Latinoware Rails 2009
 
An Introduction To jQuery
An Introduction To jQueryAn Introduction To jQuery
An Introduction To jQuery
 
IT Depends: Custom vs Packaged Software
IT Depends: Custom vs Packaged SoftwareIT Depends: Custom vs Packaged Software
IT Depends: Custom vs Packaged Software
 
Ecossistema Rails Campus Party 09
Ecossistema Rails   Campus Party 09Ecossistema Rails   Campus Party 09
Ecossistema Rails Campus Party 09
 
Hacking Movable Type Training - Day 2
Hacking Movable Type Training - Day 2Hacking Movable Type Training - Day 2
Hacking Movable Type Training - Day 2
 
Ajax
AjaxAjax
Ajax
 
Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)
 
Google Analytics and Sungard HE Luminis
Google Analytics and Sungard HE LuminisGoogle Analytics and Sungard HE Luminis
Google Analytics and Sungard HE Luminis
 
Adventurous Merb
Adventurous MerbAdventurous Merb
Adventurous Merb
 
Semcomp de São Carlos
Semcomp de São CarlosSemcomp de São Carlos
Semcomp de São Carlos
 
Debugging Django
Debugging DjangoDebugging Django
Debugging Django
 
Javascript: Ajax & DOM Manipulation v1.2
Javascript: Ajax & DOM Manipulation v1.2Javascript: Ajax & DOM Manipulation v1.2
Javascript: Ajax & DOM Manipulation v1.2
 
Front end performance (RailsWayCon 2009 short talk)
Front end performance (RailsWayCon 2009 short talk)Front end performance (RailsWayCon 2009 short talk)
Front end performance (RailsWayCon 2009 short talk)
 
シックス・アパート・フレームワーク
シックス・アパート・フレームワークシックス・アパート・フレームワーク
シックス・アパート・フレームワーク
 
Lightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClientLightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClient
 
Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On Rails
 
jQuery Internals + Cool Stuff
jQuery Internals + Cool StuffjQuery Internals + Cool Stuff
jQuery Internals + Cool Stuff
 

More from Ben Scofield

How to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsHow to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsBen Scofield
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUGBen Scofield
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
 
Open Source: A Call to Arms
Open Source: A Call to ArmsOpen Source: A Call to Arms
Open Source: A Call to ArmsBen Scofield
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud CastlesBen Scofield
 
Intentionality: Choice and Mastery
Intentionality: Choice and MasteryIntentionality: Choice and Mastery
Intentionality: Choice and MasteryBen Scofield
 
Mastery or Mediocrity
Mastery or MediocrityMastery or Mediocrity
Mastery or MediocrityBen Scofield
 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty HammerBen Scofield
 
Mind Control - DevNation Atlanta
Mind Control - DevNation AtlantaMind Control - DevNation Atlanta
Mind Control - DevNation AtlantaBen Scofield
 
Understanding Mastery
Understanding MasteryUnderstanding Mastery
Understanding MasteryBen Scofield
 
Mind Control: Psychology for the Web
Mind Control: Psychology for the WebMind Control: Psychology for the Web
Mind Control: Psychology for the WebBen Scofield
 
The State of NoSQL
The State of NoSQLThe State of NoSQL
The State of NoSQLBen Scofield
 
NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010Ben Scofield
 
NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)Ben Scofield
 
Charlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardCharlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardBen Scofield
 
WindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardWindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardBen Scofield
 
"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative DatabasesBen Scofield
 
Mind Control on the Web
Mind Control on the WebMind Control on the Web
Mind Control on the WebBen Scofield
 
How the Geeks Inherited the Earth
How the Geeks Inherited the EarthHow the Geeks Inherited the Earth
How the Geeks Inherited the EarthBen Scofield
 

More from Ben Scofield (20)

How to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsHow to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 Steps
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUG
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
Thinking Small
Thinking SmallThinking Small
Thinking Small
 
Open Source: A Call to Arms
Open Source: A Call to ArmsOpen Source: A Call to Arms
Open Source: A Call to Arms
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
Intentionality: Choice and Mastery
Intentionality: Choice and MasteryIntentionality: Choice and Mastery
Intentionality: Choice and Mastery
 
Mastery or Mediocrity
Mastery or MediocrityMastery or Mediocrity
Mastery or Mediocrity
 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty Hammer
 
Mind Control - DevNation Atlanta
Mind Control - DevNation AtlantaMind Control - DevNation Atlanta
Mind Control - DevNation Atlanta
 
Understanding Mastery
Understanding MasteryUnderstanding Mastery
Understanding Mastery
 
Mind Control: Psychology for the Web
Mind Control: Psychology for the WebMind Control: Psychology for the Web
Mind Control: Psychology for the Web
 
The State of NoSQL
The State of NoSQLThe State of NoSQL
The State of NoSQL
 
NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010
 
NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)
 
Charlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardCharlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is Hard
 
WindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardWindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is Hard
 
"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases
 
Mind Control on the Web
Mind Control on the WebMind Control on the Web
Mind Control on the Web
 
How the Geeks Inherited the Earth
How the Geeks Inherited the EarthHow the Geeks Inherited the Earth
How the Geeks Inherited the Earth
 

Recently uploaded

Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 

Recently uploaded (20)

Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 

Page Caching Resurrected: A Fairy Tale

  • 1. Page Caching Resurrected: Ben Sco eld – Viget Labs Sunday, March 22, 2009
  • 2. Page Caching Resurrected: A Fairy Tale Ben Sco eld – Viget Labs Sunday, March 22, 2009
  • 3. I’m a Rails guy Sunday, March 22, 2009
  • 4. and this is a Rails talk Sunday, March 22, 2009
  • 5. but this isn’t just for Rails Sunday, March 22, 2009
  • 11. class PigsController caches_page :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_page :action => :show end end Sunday, March 22, 2009
  • 12. Standard 1 Page 3000 requests per second Sunday, March 22, 2009
  • 13. public dynamic content Sunday, March 22, 2009
  • 17. class PigsController require_login :show caches_action :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_action :action => :show end end Sunday, March 22, 2009
  • 18. Standard 1 Action 500 Page 3000 requests per second Sunday, March 22, 2009
  • 19. dynamic content Sunday, March 22, 2009
  • 25. <% cache(:key => 'index:piglist') do %> <ul id=quot;pig-listquot;> <% @pigs.each do |pig| %> <li> <%= image_tag pig.house.photo %> <%= h pig.name %> </li> <% end %> </ul> <% end %> Sunday, March 22, 2009
  • 26. class PigsController # ... def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_fragment :key => 'index:piglist' end end Sunday, March 22, 2009
  • 27. Standard 1 Fragment 20 Action 500 Page 3000 requests per second Sunday, March 22, 2009
  • 32. class BigBadWolf def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/threaten/ [ 200, {quot;Content-Typequot; => quot;text/htmlquot;}, quot;Little pig, little pig, let me in!quot; ] else [ 404, {quot;Content-Typequot; => quot;text/htmlquot;}, quot;Not Foundquot; ] end end end Sunday, March 22, 2009
  • 44. <script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) && $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]>*/</script> Sunday, March 22, 2009
  • 45. <ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;> <li id=quot;welcome-usernamequot; class=quot;firstquot;> Welcome </li> <li> <a href=quot;/profilequot; class=quot;utility-linkquot;>Profile</a> </li> <li> <a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;>Queue</a> </li> <li class=quot;sign-out-linkquot;> <a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;>Sign Out</a> </li> </ul> <ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot;> <li class=quot;first sign-out-linkquot;> <a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot; onclick=quot;Login.show($('top-login-form')); return false;quot;>Login</a> </li> <li class=quot;signin-border-leftquot;> <a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;>Forgot Password?</a> </li> <li class=quot;signin-border-leftquot;> <a href=quot;/signupquot; class=quot;utility-linkquot;>Sign Up</a> </li> </ul> Sunday, March 22, 2009
  • 46. <noscript> <ul class=quot;nojs usernavquot;> <li> Please <a href=quot;/support/quot;>enable javascript</a> to log in. </li> </ul> </noscript> <div id=quot;top-login-formquot; class=quot;usernav login-formquot; style=quot;display:nonequot;> <form action=quot;https://secure.hulu.com/account/authenticatequot; method=quot;getquot; name=quot;login-formquot; onsubmit=quot;Login.submit(this); return false;quot;> <span class=quot;login-statusquot;></span> <input id=quot;loginquot; class=quot;active loginquot; type=quot;textquot; style=quot;display: none;quot; name=quot;usernamequot;/> <input id=quot;passwordquot; class=quot;active passwordquot; type=quot;passwordquot; style=quot;display: none;quot; name=quot;passwordquot;/> <input class=quot;inactive dummy loginquot; type=quot;textquot; value=quot;usernamequot; name=quot;dummy_loginquot; /> <input class=quot;inactive dummyquot; type=quot;textquot; value=quot;passwordquot; name=quot;dummy_passwordquot; /> <input alt=quot;Loginquot; class=quot;login-submitquot; src=quot;http://static.hulu.com/images/btn-signin-small.gif?1237361096quot; style=quot;width: 39px; height: 20;quot; type=quot;imagequot; /> <a href=quot;#quot;><img alt=quot;Cancelquot; border=quot;0quot; class=quot;hover-mequot; height=quot;20quot; id=quot;btn-x.gif123741536309506quot; onclick=quot;Login.cancel();return falsequot; src=quot;http://static.hulu.com/images/btn-x.gif?1237361096quot; width=quot;18quot; /></a> </form> <a href=quot;/signupquot; class=quot;utility-linkquot;>Sign Up</a> </div> Sunday, March 22, 2009
  • 47. <ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;> <li id=quot;welcome-usernamequot; class=quot;firstquot;> Welcome </li> <li> <a href=quot;/profilequot; class=quot;utility-linkquot;>Profile</a> </li> <li> <a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;>Queue</a> </li> <li class=quot;sign-out-linkquot;> <a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;>Sign Out</a> </li> </ul> <ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot;> <li class=quot;first sign-out-linkquot;> <a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot; onclick=quot;Login.show($('top-login-form')); return false;quot;>Login</a> </li> <li class=quot;signin-border-leftquot;> <a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;>Forgot Password?</a> </li> <li class=quot;signin-border-leftquot;> <a href=quot;/signupquot; class=quot;utility-linkquot;>Sign Up</a> </li> </ul> Sunday, March 22, 2009
  • 49. hulu is insane don’t do it like they do Sunday, March 22, 2009
  • 50. <script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) && $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]>*/</script> Sunday, March 22, 2009
  • 51. <script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) && $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]>*/</script> Sunday, March 22, 2009
  • 52. the* right way *a Sunday, March 22, 2009
  • 56. class ItemsController < ApplicationController def index @user = User.find_by_login(params[:user]) @items = Item.released_on(params[:date]) end end Sunday, March 22, 2009
  • 57. class Item < ActiveRecord::Base has_many :pulls, :dependent => :destroy named_scope :released_on, lambda { |date| date ||= Item.maximum(:released_on) {:conditions => {:released_on => date}, :order => 'name ASC'} } def pulled_by?(user) x = user.nil? ? false : !self.pulls.by_user(user.id).empty? end end Sunday, March 22, 2009
  • 58. <h1>Releases</h1> <ul> <% @items.each do |item| %> <% content_tag_for :li, item do %> <%= image_tag 'cover.png', :alt => h(item.name), :class => 'cover' %> <%= image_tag('badge.png', :alt => 'pulling',:class => 'badge') if item.pulled_by?(@user) %> <p><%= h item.name %></p> <% end %> <% end %> </ul> Sunday, March 22, 2009
  • 59. the hybrid approach Sunday, March 22, 2009
  • 60. class ItemsController < ApplicationController caches_page :index def index @items = Item.released_on(params[:date]).all end end Sunday, March 22, 2009
  • 61. require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless defined?(Rails) class PullList def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/pulls/ date = '2008-11-05' user = '1' [ 200, {quot;Content-Typequot; => quot;application/javascriptquot;}, [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]] else [404, {quot;Content-Typequot; => quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end Sunday, March 22, 2009
  • 62. class Pull < ActiveRecord::Base belongs_to :user belongs_to :item named_scope :by_user, lambda { |user_id| {:conditions => {:user_id => user_id}} } named_scope :for_date, lambda { |date| {:include => :item, :conditions => {:items => {:released_on => date}}} } end Sunday, March 22, 2009
  • 63. $(document).ready(function() { $.getJSON('/pulls', function(data) { $.each(data, function() { $('#item_'+this).addClass('pulled'); }); }); }); Sunday, March 22, 2009
  • 68. Standard 0.617 Hybrid 0.039 0.096 content load time Sunday, March 22, 2009
  • 69. when to use it Sunday, March 22, 2009
  • 76. no shirt, no javascript, no service Sunday, March 22, 2009
  • 77. Thank You ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/speakers/44 Sunday, March 22, 2009

Editor's Notes

  1. 3 minutes
  2. super simple to use, but results in PUBLIC content
  3. more framework-specific; solves auth-protected pages, etc. - cached content is not publicly available
  4. caches only specific parts of the page, which are not publically available
  5. expiration of each fragment, individually
  6. 10 minutes
  7. 15 minutes
  8. 22 minutes
  9. 26 minutes
  10. 32 minutes
  11. 135ms for hybrid, which is 21% of the standard lame tests I employed showed the same or greater effect
  12. 34 minutes