Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rails Engines - Lessons Learned

Rails Engines - Lessons Learned

This talk was performed at SpreeConf 2012 and a slightly shorter/modified version at Ruby on Ales in Bend Oregon, March 2012.

It covers the lessons that I've learned from building engines and working with them on massive scale applications. Two engines mentioned prominently in this talk are the Forem (https://github.com/radar/forem) and Spree (https://github.com/spree/spree), with some mentions of others, such as Devise.

Great information for those looking to get started with engines!

Ryan Bigg

March 03, 2012
Tweet

More Decks by Ryan Bigg

Other Decks in Programming

Transcript

  1. Saturday, 3 March 12

    View Slide

  2. How my
    curiosity
    about new
    features in
    Ruby on Rails...
    Saturday, 3 March 12

    View Slide

  3. ...
    kind of
    sort of...
    Saturday, 3 March 12

    View Slide

  4. ...indirectly led me to
    getting a new job...
    Saturday, 3 March 12

    View Slide

  5. ...where I do
    awesome
    “stuff”...
    Saturday, 3 March 12

    View Slide

  6. ...for an
    awesome
    community...
    Saturday, 3 March 12

    View Slide

  7. ...and exactly what
    that awesome
    “stuff” entails.
    Saturday, 3 March 12

    View Slide

  8. aka
    “Namespacing: Good for
    the soul”
    Saturday, 3 March 12

    View Slide

  9. Ryan
    Bigg
    Saturday, 3 March 12

    View Slide

  10. Ryan
    Bigg
    @ryanbigg
    Saturday, 3 March 12

    View Slide

  11. Ryan
    Bigg
    Radar
    @ryanbigg
    Saturday, 3 March 12

    View Slide

  12. Saturday, 3 March 12

    View Slide

  13. Saturday, 3 March 12

    View Slide

  14. Saturday, 3 March 12

    View Slide

  15. Saturday, 3 March 12

    View Slide

  16. Saturday, 3 March 12

    View Slide

  17. Saturday, 3 March 12

    View Slide

  18. Saturday, 3 March 12

    View Slide

  19. Saturday, 3 March 12

    View Slide

  20. 26,890
    reputation
    top 0.67% of all time
    Saturday, 3 March 12

    View Slide

  21. Saturday, 3 March 12

    View Slide

  22. 1%
    Saturday, 3 March 12

    View Slide

  23. Saturday, 3 March 12

    View Slide

  24. Community
    Manager
    Community
    Manager
    Saturday, 3 March 12

    View Slide

  25. Saturday, 3 March 12

    View Slide

  26. Saturday, 3 March 12

    View Slide

  27. Saturday, 3 March 12

    View Slide

  28. Saturday, 3 March 12

    View Slide

  29. Saturday, 3 March 12

    View Slide

  30. Saturday, 3 March 12

    View Slide

  31. Saturday, 3 March 12

    View Slide

  32. 1,784 commits
    Saturday, 3 March 12

    View Slide

  33. 1,784 commits
    (or roughly, 30%)
    Saturday, 3 March 12

    View Slide

  34. Engines
    Engines
    Saturday, 3 March 12

    View Slide

  35. James
    Adam
    James
    Adam
    Saturday, 3 March 12

    View Slide

  36. Oct 31,
    2005
    Oct 31,
    2005
    Saturday, 3 March 12

    View Slide

  37. 0.14.2
    0.14.2
    Rails
    Rails
    Saturday, 3 March 12

    View Slide

  38. Kevin
    Smith
    Kevin
    Smith
    Saturday, 3 March 12

    View Slide

  39. “[engines are a]
    nasty hack that
    breaks every new
    version of Rails”
    http://glu.ttono.us/articles/2006/08/30/guide-things-you-shouldnt-be-doing-in-rails
    Saturday, 3 March 12

    View Slide

  40. “Stop trying to
    write ‘neato ajax
    driven thingies’”
    http://glu.ttono.us/articles/2006/08/30/guide-things-you-shouldnt-be-doing-in-rails
    Saturday, 3 March 12

    View Slide

  41. Saturday, 3 March 12

    View Slide

  42. “I didn't want Rails to succumb
    to the lure of high-level
    components like login systems,
    forums, content management,
    and the likes.” - DHH
    http://david.heinemeierhansson.com/arc/000407.html
    Saturday, 3 March 12

    View Slide

  43. Saturday, 3 March 12

    View Slide

  44. Saturday, 3 March 12

    View Slide

  45. Saturday, 3 March 12

    View Slide

  46. Saturday, 3 March 12

    View Slide

  47. “But the goal of Rails is to
    create a world where [engines]
    are neither needed or strongly
    desired. Obviously, we are not
    quite there yet.” - DHH
    http://weblog.rubyonrails.org/2005/11/11/why-engines-and-
    components-are-not-evil-but-distracting
    Saturday, 3 March 12

    View Slide

  48. “Engines have not received the
    blessing of the RoR core team,
    and I wouldn't expect any
    different, because it would be
    madness to include them in the
    core Rails.” - James Adam
    http://article.gmane.org/gmane.comp.lang.ruby.rails/29166
    Saturday, 3 March 12

    View Slide

  49. Madness!
    Saturday, 3 March 12

    View Slide

  50. Engine Support
    Rails < 2.3
    Use engines plugin
    https://github.com/lazyatom/engines
    Saturday, 3 March 12

    View Slide

  51. Engine Support
    Rails 2.3
    LOL
    http://railscasts.com/episodes/149-rails-engines
    Saturday, 3 March 12

    View Slide

  52. Yehuda
    Katz
    Yehuda
    Katz
    Saturday, 3 March 12

    View Slide

  53. Piotr
    Sarnacki
    Piotr
    Sarnacki
    Saturday, 3 March 12

    View Slide

  54. Saturday, 3 March 12

    View Slide

  55. Engine Support
    Rails 3.0 - Not bad
    Saturday, 3 March 12

    View Slide

  56. Engine Support
    Rails 3.1 - OH YEAH
    Saturday, 3 March 12

    View Slide

  57. Saturday, 3 March 12

    View Slide

  58. Saturday, 3 March 12

    View Slide

  59. Before
    Spree 1.0
    Saturday, 3 March 12

    View Slide

  60. Saturday, 3 March 12

    View Slide

  61. Spree
    Product
    App
    path/to/engine/app/models/product.rb
    Product
    Saturday, 3 March 12

    View Slide

  62. Spree
    Product
    App
    Product
    path/to/app/app/models/product.rb
    path/to/engine/app/models/product.rb
    Product
    Saturday, 3 March 12

    View Slide

  63. Saturday, 3 March 12

    View Slide

  64. ~300 lines of
    documentation
    Rails::Engine
    Saturday, 3 March 12

    View Slide

  65. rails plugin new blorgh
    Saturday, 3 March 12

    View Slide

  66. rails plugin new blorgh --full
    Saturday, 3 March 12

    View Slide

  67. rails plugin new blorgh --full --mountable
    Saturday, 3 March 12

    View Slide

  68. A gem
    by default
    Saturday, 3 March 12

    View Slide

  69. gem ‘blorgh’, :git =>
    ‘git://github.com/radar/blorgh’
    Saturday, 3 March 12

    View Slide

  70. Step away
    from the
    Gemfile
    Saturday, 3 March 12

    View Slide

  71. blorgh.gemspec
    Saturday, 3 March 12

    View Slide

  72. blorgh.gemspec
    s.add_development_dependency
    Saturday, 3 March 12

    View Slide

  73. blorgh.gemspec
    s.add_development_dependency
    s.add_dependency
    Saturday, 3 March 12

    View Slide

  74. lib/blorgh.rb
    require ‘blorgh/engine’
    module Blorgh
    end
    Saturday, 3 March 12

    View Slide

  75. lib/blorgh/engine.rb
    module Blorgh
    class Engine < Rails::Engine
    end
    end
    Saturday, 3 March 12

    View Slide

  76. initializer “something” do
    # your code here
    end
    Inside Blorgh::Engine
    Saturday, 3 March 12

    View Slide

  77. Inside Blorgh::Engine
    config.generators do |g|
    g.orm :webscale
    end
    Saturday, 3 March 12

    View Slide

  78. Rails::Application <
    Rails::Engine
    Saturday, 3 March 12

    View Slide

  79. “In Rails 3.0, a Rails::Application
    object was introduced which is
    nothing more than an Engine but
    with the responsibility of
    coordinating the whole boot process.”
    Rails::Application
    Saturday, 3 March 12

    View Slide

  80. Saturday, 3 March 12

    View Slide

  81. Inside Blorgh::Engine
    endpoint SomeRackApp
    Saturday, 3 March 12

    View Slide

  82. Rakefile
    (tasks go into lib/tasks)
    Saturday, 3 March 12

    View Slide

  83. config
    initializers
    locales
    routes
    Saturday, 3 March 12

    View Slide

  84. Generators
    Saturday, 3 March 12

    View Slide

  85. blorgh:install:migrations
    Comes standard
    Saturday, 3 March 12

    View Slide

  86. GOOD
    README
    not included
    but for the love of God
    write one
    Saturday, 3 March 12

    View Slide

  87. The best Rails 3.1 forum system.
    Saturday, 3 March 12

    View Slide

  88. The best Rails 3.1 forum system.
    Ever.
    Saturday, 3 March 12

    View Slide

  89. Namespacing
    Namespacing
    Saturday, 3 March 12

    View Slide

  90. rails g model post
    Saturday, 3 March 12

    View Slide

  91. rails g model post
    app/models/post.rb
    Saturday, 3 March 12

    View Slide

  92. Forem
    Post
    App
    path/to/engine/app/models/post.rb
    Post
    Saturday, 3 March 12

    View Slide

  93. Forem
    Post
    App
    Post
    path/to/app/app/models/post.rb
    path/to/engine/app/models/post.rb
    Post
    Saturday, 3 March 12

    View Slide

  94. “Just call it
    something
    different”
    Saturday, 3 March 12

    View Slide

  95. Yeah.
    Nah.
    Saturday, 3 March 12

    View Slide

  96. isolate_namespace Forem
    Saturday, 3 March 12

    View Slide

  97. rails g model post
    Saturday, 3 March 12

    View Slide

  98. rails g model post
    app/models/forem/post.rb
    Saturday, 3 March 12

    View Slide

  99. Forem ::
    Post
    App
    path/to/engine/app/models/forem/post.rb
    Post
    Saturday, 3 March 12

    View Slide

  100. Forem ::
    Post
    App
    Post
    path/to/app/app/models/post.rb
    path/to/engine/app/models/forem/post.rb
    Post
    Saturday, 3 March 12

    View Slide

  101. forem_posts
    Saturday, 3 March 12

    View Slide

  102. Forem::PostsController
    forem_posts
    Saturday, 3 March 12

    View Slide

  103. Forem::PostsController
    app/views/forem/posts
    forem_posts
    Saturday, 3 March 12

    View Slide

  104. Rails.application.routes.draw
    Saturday, 3 March 12

    View Slide

  105. Rails.application.routes.draw do
    namespace :forem do
    resources :forums
    end
    end
    forem/config/routes.rb
    Saturday, 3 March 12

    View Slide

  106. Rails.application.routes.draw
    Saturday, 3 March 12

    View Slide

  107. Forem::Engine.routes.draw
    Rails.application.routes.draw
    Saturday, 3 March 12

    View Slide

  108. Forem::Engine.routes.draw do
    resources :forums
    ...
    end
    forem/config/routes.rb
    Saturday, 3 March 12

    View Slide

  109. mount Forem::Engine, :at => “forum”
    the_app/config/routes.rb
    Saturday, 3 March 12

    View Slide

  110. forums_path
    /forum/forums
    Saturday, 3 March 12

    View Slide

  111. forums_path
    forem.
    /forum/forums
    Saturday, 3 March 12

    View Slide

  112. dropbears_path
    /dropbears
    Saturday, 3 March 12

    View Slide

  113. dropbears_path
    main_app.
    /dropbears
    Saturday, 3 March 12

    View Slide

  114. form_for [forem, @topic, @post]
    Saturday, 3 March 12

    View Slide

  115. form_for [forem, @topic, @post]
    /forums/topics/1/posts
    Saturday, 3 March 12

    View Slide

  116. Hard
    Problems
    Saturday, 3 March 12

    View Slide

  117. HOW 2
    SHOT
    AUTH?
    Saturday, 3 March 12

    View Slide

  118. spree_auth
    Saturday, 3 March 12

    View Slide

  119. http://aubenoire.files.wordpress.com/2011/05/not-my-problem.jpg
    Saturday, 3 March 12

    View Slide

  120. class ApplicationController
    def forem_user
    current_user
    end
    end
    Saturday, 3 March 12

    View Slide

  121. Forem.user_class = “User”
    config/initializers/forem.rb
    Into
    Put
    Saturday, 3 March 12

    View Slide

  122. User#to_s
    Saturday, 3 March 12

    View Slide

  123. Authlogic
    Saturday, 3 March 12

    View Slide

  124. Devise
    Saturday, 3 March 12

    View Slide

  125. Custom
    Saturday, 3 March 12

    View Slide

  126. HOW 2
    SHOT AUTH?
    (part two)
    Saturday, 3 March 12

    View Slide

  127. CanCan
    CanCan
    Saturday, 3 March 12

    View Slide

  128. <% if can?(:read, category) %>
    Saturday, 3 March 12

    View Slide

  129. Forem::DefaultPermissions
    Saturday, 3 March 12

    View Slide

  130. Forem::DefaultPermissions
    can_read_forem_forum?(forum)
    can_read_forem_category?(category)
    Saturday, 3 March 12

    View Slide

  131. can_read_forem_forum?(forum)
    def
    true
    end
    Saturday, 3 March 12

    View Slide

  132. def can_read_forem_forum?(forum)
    # your code goes here
    end
    app/models/user.rb
    Saturday, 3 March 12

    View Slide

  133. module Forem
    class Ability
    include CanCan::Ability
    def initialize(user)
    user ||= Forem.user_class.constantize.new
    can :read, Forem::Category do |category|
    user.can_read_forem_category?(category)
    end
    ...
    Saturday, 3 March 12

    View Slide

  134. module Forem
    class Ability
    include CanCan::Ability
    def initialize(user)
    user ||= Forem.user_class.constantize.new
    can :read, Forem::Category do |category|
    user.can_read_forem_category?(category)
    end
    ...
    Saturday, 3 March 12

    View Slide

  135. class Forem::ApplicationController
    def current_ability
    Forem::Ability.new(forem_user)
    end
    ...
    end
    Saturday, 3 March 12

    View Slide

  136. <% if can?(:read, category) %>
    Saturday, 3 March 12

    View Slide

  137. Theming
    Saturday, 3 March 12

    View Slide

  138. stylesheet_link_tag “forem/theme/twist”
    app/views/layouts/
    forem.html.erb
    Saturday, 3 March 12

    View Slide

  139. module Forem
    module Theme
    module Twist
    class Engine < Rails::Engine
    end
    end
    end
    end
    Saturday, 3 March 12

    View Slide

  140. Rails::Engine
    \m/
    Saturday, 3 March 12

    View Slide

  141. app/assets/stylesheets/
    forem/theme/twist.css
    forem-theme-twist
    Saturday, 3 March 12

    View Slide

  142. app/assets/stylesheets/
    forem/theme/twist.css
    forem-theme-twist
    javascript + images too!
    Saturday, 3 March 12

    View Slide

  143. Install
    + Setup
    Saturday, 3 March 12

    View Slide

  144. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    Saturday, 3 March 12

    View Slide

  145. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    Saturday, 3 March 12

    View Slide

  146. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rake forem:install:migrations
    Saturday, 3 March 12

    View Slide

  147. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rake forem:install:migrations
    rake db:migrate
    Saturday, 3 March 12

    View Slide

  148. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rake forem:install:migrations
    rake db:migrate
    create config/initializers/forem.rb
    Saturday, 3 March 12

    View Slide

  149. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rake forem:install:migrations
    rake db:migrate
    create config/initializers/forem.rb
    Add forem_user method to AppController
    Saturday, 3 March 12

    View Slide

  150. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rake forem:install:migrations
    rake db:migrate
    create config/initializers/forem.rb
    Add forem_user method to AppController
    Add User#to_s method
    Saturday, 3 March 12

    View Slide

  151. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rake forem:install:migrations
    rake db:migrate
    create config/initializers/forem.rb
    Add forem_user method to AppController
    Add User#to_s method
    Go into console + create first forum
    Saturday, 3 March 12

    View Slide

  152. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rake forem:install:migrations
    rake db:migrate
    create config/initializers/forem.rb
    Add forem_user method to AppController
    Add User#to_s method
    Go into console + create first forum
    Mount Forem::Engine, :at => ‘/’
    Saturday, 3 March 12

    View Slide

  153. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rake forem:install:migrations
    rake db:migrate
    Pray that it works.
    create config/initializers/forem.rb
    Add forem_user method to AppController
    Add User#to_s method
    Go into console + create first forum
    Mount Forem::Engine, :at => ‘/’
    Saturday, 3 March 12

    View Slide

  154. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    Saturday, 3 March 12

    View Slide

  155. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    Saturday, 3 March 12

    View Slide

  156. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rails g forem:install
    Saturday, 3 March 12

    View Slide

  157. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rails g forem:install
    Answer two questions.
    Saturday, 3 March 12

    View Slide

  158. gem ‘forem’,
    :git => “git://github.com/radar/forem”
    bundle install
    rails g forem:install
    It works!
    Answer two questions.
    (assuming you have a User model)
    Saturday, 3 March 12

    View Slide

  159. Spree 1.0
    Saturday, 3 March 12

    View Slide

  160. Namespace
    everything
    Saturday, 3 March 12

    View Slide

  161. SpreeCore
    Saturday, 3 March 12

    View Slide

  162. Spree::Core
    Spree::Auth
    Saturday, 3 March 12

    View Slide

  163. Spree ::Core::Product
    Saturday, 3 March 12

    View Slide

  164. Spree ::Product
    Saturday, 3 March 12

    View Slide

  165. Spree::
    Product
    App
    Product
    path/to/app/app/models/product.rb
    path/to/engine/app/models/spree/product.rb
    Product
    Saturday, 3 March 12

    View Slide

  166. Spree::
    Product
    App
    Product
    path/to/app/app/models/product.rb
    path/to/engine/app/models/spree/product.rb
    Product
    Saturday, 3 March 12

    View Slide

  167. Forem
    Forem
    Saturday, 3 March 12

    View Slide

  168. Forem
    App
    Forem
    Saturday, 3 March 12

    View Slide

  169. Forem::Engine.routes.draw
    Saturday, 3 March 12

    View Slide

  170. mount Forem::Engine, :at => “forums”
    Saturday, 3 March 12

    View Slide

  171. Core
    Auth API
    Promo
    Dash
    Spree
    Saturday, 3 March 12

    View Slide

  172. Core
    Auth API
    Promo
    Dash
    App
    Spree
    Saturday, 3 March 12

    View Slide

  173. Spree::Core::Engine.routes.draw
    Spree::Auth::Engine.routes.draw
    Spree::Promo::Engine.routes.draw
    Spree::Dash::Engine.routes.draw
    Spree::Api::Engine.routes.draw
    Saturday, 3 March 12

    View Slide

  174. mount Spree::Core::Engine, :at => ‘/’
    mount Spree::Auth::Engine, :at => ‘/’
    mount Spree::Api::Engine, :at => ‘/’
    mount Spree::Dash::Engine, :at => ‘/’
    mount Spree::Promo::Engine, :at => ‘/’
    Saturday, 3 March 12

    View Slide

  175. mount Spree::Core::Engine, :at => ‘/’
    mount Spree::Auth::Engine, :at => ‘/’
    mount Spree::Api::Engine, :at => ‘/’
    mount Spree::Dash::Engine, :at => ‘/’
    mount Spree::Promo::Engine, :at => ‘/’
    mount Spree::YourExtension, :at => ‘/’
    mount Spree::YourExtension, :at => ‘/’
    mount Spree::YourExtension, :at => ‘/’
    mount Spree::YourExtension, :at => ‘/’
    Saturday, 3 March 12

    View Slide

  176. spree_core.root_path
    spree_auth.login_path
    Saturday, 3 March 12

    View Slide

  177. HAHAHAHAHAHAHAHAHAH
    AHAHAHAHAHAHAHAHAHA
    HAHAHAHAHAHAHAHAHAH
    AHAHAHAHAHAHAHAHAHA
    HAHAHAHAHAHAHAHAHAH
    AHAHAHAHAHAHAHAHAHA
    HAHAHAHAHAHAHAHAHAH
    AHAHAHAHAHAHAHAHAHA
    HAHAHAHAHAHAHAHAHAH
    AHAHAHAHAHAHAHAHAHA
    HAHAHAHAHAHAHAHAHAH
    Saturday, 3 March 12

    View Slide

  178. mount Spree::Core::Engine, :at => ‘/’
    Saturday, 3 March 12

    View Slide

  179. spree.login_path
    spree.root_path
    Saturday, 3 March 12

    View Slide

  180. Spree::Core::Engine.routes.prepend
    Saturday, 3 March 12

    View Slide

  181. Spree::Core::Engine.routes.prepend do
    mount Spree::Auth::Engine, :as => “spree”
    end
    Saturday, 3 March 12

    View Slide

  182. Core
    Auth API
    Promo
    Dash
    App
    Extensions
    Saturday, 3 March 12

    View Slide

  183. Core
    Auth API
    Promo
    Dash
    App
    Extensions
    Saturday, 3 March 12

    View Slide

  184. Fix
    everything
    Saturday, 3 March 12

    View Slide

  185. describe Spree::ProductsController do
    it “gets a list of products” do
    get :index
    end
    end
    spec/controllers/products_controller_spec.rb
    Saturday, 3 March 12

    View Slide

  186. describe Spree::ProductsController do
    it “gets a list of products” do
    get :index
    end
    end
    spec/controllers/products_controller_spec.rb
    No route matches { :controller =>
    “Spree::ProductsController”, :action
    => “index” }
    Saturday, 3 March 12

    View Slide

  187. Saturday, 3 March 12

    View Slide

  188. http://stackoverflow.com/a/5832908/15245
    How do I write a Rails 3.1
    engine controller test in
    RSpec?
    The workaround is quite simple, instead of this
    get  :show,  :id  =>  1
    use this
    get  :show,  {:id  =>  1,  :use_route  =>  :posts}
    Saturday, 3 March 12

    View Slide

  189. Well,
    duh.
    Saturday, 3 March 12

    View Slide

  190. :use_route  =>  :spree
    Saturday, 3 March 12

    View Slide

  191. Saturday, 3 March 12

    View Slide

  192. rails-3.1 (3-1-stable)♐ ack ":use_route"
    actionpack/lib/action_dispatch/routing/route_set.rb
    actionpack/test/controller/routing_test.rb
    actionpack/test/template/form_helper_test.rb
    Saturday, 3 March 12

    View Slide

  193. rails-3.1 (3-1-stable)♐ ack ":use_route"
    actionpack/lib/action_dispatch/routing/route_set.rb
    actionpack/test/controller/routing_test.rb
    actionpack/test/template/form_helper_test.rb
    Three files.
    No comments.
    No description.
    Saturday, 3 March 12

    View Slide

  194. Saturday, 3 March 12

    View Slide

  195. Magic.
    Saturday, 3 March 12

    View Slide

  196. Fixed
    everything
    Saturday, 3 March 12

    View Slide

  197. Bug fixes
    too!
    (thanks!)
    Saturday, 3 March 12

    View Slide

  198. Spree 1.0
    is the now
    Saturday, 3 March 12

    View Slide

  199. Use it.
    (Please)
    Saturday, 3 March 12

    View Slide

  200. One more
    thing...
    Saturday, 3 March 12

    View Slide

  201. I lied to you.
    I’m sorry.
    Saturday, 3 March 12

    View Slide

  202. Really.
    Really.
    Saturday, 3 March 12

    View Slide

  203. Saturday, 3 March 12

    View Slide

  204. Enjoy.
    Enjoy.
    Saturday, 3 March 12

    View Slide

  205. Enjoy.
    Enjoy.
    Thanks!
    Saturday, 3 March 12

    View Slide