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

Rails Engines as an SOA Middle Ground

Rails Engines as an SOA Middle Ground

Jeff Felchner

January 28, 2014
Tweet

More Decks by Jeff Felchner

Other Decks in Technology

Transcript

  1. Rails Engines
    as an
    SOA Middle Ground

    View full-size slide

  2. Before We Begin

    View full-size slide

  3. I DON’T ALWAYS SAY ALWAYS
    BUT WHEN I DO
    I ALMOST NEVER MEAN IT

    View full-size slide

  4. Have You Been Here?

    View full-size slide

  5. WE FEAR CHANGE

    View full-size slide

  6. Object-Orientation

    View full-size slide

  7. $ bundle update my_engine

    View full-size slide

  8. gem  'my_engine',
           :path  =>  '/path/to/my/engine'

    View full-size slide

  9. "This might make a nice
    open source project."

    View full-size slide

  10. "If I don't release it to
    rubygems.org, how do I use it
    in my projects?"

    View full-size slide

  11. Add it to your GEM_PATH manually

    View full-size slide

  12. $ export GEM_PATH=/path/to/gem;$GEM_PATH

    View full-size slide

  13. Use a private git repo in your Gemfile

    View full-size slide

  14. gem  'my_engine',
           :git  =>  '/path/to/my/git/repo'

    View full-size slide

  15. Use a local gem server

    View full-size slide

  16. $ gem server

    View full-size slide

  17. $ gem sources --add http://localhost:8808

    View full-size slide

  18. source ‘http://localhost:8808’
    # Gemfile

    View full-size slide

  19. Use a 3rd party service

    View full-size slide

  20. A Type of Gem

    View full-size slide

  21. class  MyRailtie  <  Rails::Railtie
       #  Does  Stuff
    end

    View full-size slide

  22. require  ‘my_railtie’  if  const_defined?(Rails)

    View full-size slide

  23. Add Middleware

    View full-size slide

  24. Create/Update Configuration Settings

    View full-size slide

  25. Add Generators

    View full-size slide

  26. Run Code at Rails Console Load Time

    View full-size slide

  27. Add Rake Tasks

    View full-size slide

  28. Create Rails Initializers

    View full-size slide

  29. after_initialize
    app_middleware
    before_configuration
    before_eager_load
    before_initialize
    generators
    to_prepare

    View full-size slide

  30. module  RSpec
    module  Rails
    class    Railtie  <  ::Rails::Railtie
       config.generators.integration_tool  :rspec
       config.generators.test_framework      :rspec
       rake_tasks  do
           load  "rspec/rails/tasks/rspec.rake"
       end
    end
    end
    end

    View full-size slide

  31. irb> Rails::Engine.ancestors
    # => [
           [0]  Rails::Engine  <  Rails::Railtie,
           [1]  Rails::Railtie  <  Object,
           [2]  Rails::Initializable,
           [3]  Object  <  BasicObject,
           [4]  Kernel,
           [5]  BasicObject
    ]

    View full-size slide

  32. irb> MyRailsApp::Application.ancestors
    # => [
           [0]  MyApp::Application  <  Rails::Application,
           [1]  Rails::Application  <  Rails::Engine,
           [2]  Rails::Engine  <  Rails::Railtie,
           [3]  Rails::Railtie  <  Object,
           [4]  Rails::Initializable,
           [5]  Object  <  BasicObject,
           [6]  Kernel,
           [7]  BasicObject
    ]

    View full-size slide

  33. Images
    CSS
    Javascript
    Models
    Controllers
    Observers
    Mailers
    Migrations

    View full-size slide

  34. Rails.application.routes.draw  do
       mount  MyEngine::Engine  =>  "/my_engine"
    end

    View full-size slide

  35. http://yourapp/admin

    View full-size slide

  36. ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................

    View full-size slide

  37. Gem Extraction

    View full-size slide

  38. You're formatting them
    You're converting them to latitude/longitude
    You're validating them
    You're verifying them against an external API

    View full-size slide

  39. class  Event
       include  ActiveModel::Model
       define_attribute_methods    :venue_name,            :venue_street,
                                                           :venue_city,            :venue_state,
                                                           :venue_zip_code,    :venue_country
       validates                                  :venue_name,
                                                           :presence  =>  true
       validates                                  :venue_city,
                                                           :presence  =>  {
                                                               :if  =>  :venue_partially_set?  }
       #  Lots  more  lines  of  validations...
       def  address_in_one_line_format;                #  Code  here;  end
       def  address_in_multiline_text_format;    #  Code  here;  end
       def  address_in_html_format;                        #  Code  here;  end
    end

    View full-size slide

  40. class  User
       include  ActiveModel::Model
       define_attribute_methods    :business_address_name,            :business_address_street,
                                                           :business_address_city,            :business_address_state,
                                                           :business_address_zip_code,    :business_address_country
       validates                                  :business_address_name,
                                                           :presence  =>  true
       validates                                  :business_address_city,
                                                           :presence  =>  {
                                                               :if  =>  :business_address_partially_set?  }
       #  Lots  more  lines  of  validations...
       def  address_in_one_line_format;                #  Code  here;  end
       def  address_in_multiline_text_format;    #  Code  here;  end
       def  address_in_html_format;                        #  Code  here;  end
    end

    View full-size slide

  41. class  Event
       include  ActiveModel::Model
       define_attribute_methods    :venue_name,            :venue_street,
                                                           :venue_city,            :venue_state,
                                                           :venue_zip_code,    :venue_country
       validates                                  :venue_name,
                                                           :presence  =>  true
       validates                                  :venue_city,
                                                           :presence  =>  {
                                                               :if  =>  :venue_partially_set?  }
       #  Lots  more  lines  of  validations...
       def  address_in_one_line_format;                #  Code  here;  end
       def  address_in_multiline_text_format;    #  Code  here;  end
       def  address_in_html_format;                        #  Code  here;  end
    end

    View full-size slide

  42. class  Event
       include  Pinpoint::Composable
       pinpoint  :venue
    end

    View full-size slide

  43. event  =  Event.new(some_sweet_attributes_including_an_address)
    event.venue.to_s(:one_line)
    #  =>  'Kwik-­‐E-­‐Mart,  123  Apu  Lane,  Springfield,  NW  12345,  United  States'
    event.venue.to_s(:multi_line)
    #  =>  'Kwik-­‐E-­‐Mart
    #          123  Apu  Lane
    #          Springfield,  NW  12345
    #          United  States'
    event.venue.to_s(:html)
    #  =>  '
    #              
    #                  Kwik-­‐E-­‐Mart
    #              
    #              
    #                  123  Apu  Lane
    #              
    #              
    #                  Springfield
    #                  NW
    #                  12345
    #              
    #              
    #                  United  States
    #              
    #          '

    View full-size slide

  44. event.venue.to_s(:one_line,  :country  =>  :uk)

    View full-size slide

  45. event.venue.to_s(:json)

    View full-size slide

  46. ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ...................................

    View full-size slide

  47. Engine Extraction

    View full-size slide

  48. What services does my application
    provide to its users?

    View full-size slide

  49. What would I pay someone else to do?

    View full-size slide

  50. What services are others
    creating businesses around?

    View full-size slide

  51. When placing an order for tickets, we
    provide them with a shopping cart that they
    can use to store their purchase choices and
    then give them a way to pay for them.
    Assuming that everything was successful, we
    send out an email for the receipt and the
    tickets to the user.

    View full-size slide

  52. When placing an order for tickets, we
    provide them with a shopping cart that they
    can use to store their purchase choices and
    then give them a way to pay for them.
    Assuming that everything was successful, we
    send out an email for the receipt and the
    tickets to the user.

    View full-size slide

  53. When placing an order for tickets, we
    provide them with a shopping cart that they
    can use to store their purchase choices and
    then give them a way to pay for them.
    Assuming that everything was successful, we
    send out an email for the receipt and the
    tickets to the user.

    View full-size slide

  54. When placing an order for tickets, we
    provide them with a shopping cart that they
    can use to store their purchase choices and
    then give them a way to pay for them.
    Assuming that everything was successful, we
    send out an email for the receipt and the
    tickets to the user.

    View full-size slide

  55. When placing an order for tickets, we
    provide them with a shopping cart that they
    can use to store their purchase choices and
    then give them a way to pay for them.
    Assuming that everything was successful, we
    send out an email for the receipt and the
    tickets to the user.

    View full-size slide

  56. When placing an order for tickets, we
    provide them with a shopping cart that they
    can use to store their purchase choices and
    then give them a way to pay for them.
    Assuming that everything was successful, we
    send out an email for the receipt and the
    tickets to the user.

    View full-size slide

  57. $ rails plugin new ticketing --mountable

    View full-size slide

  58. create README.rdoc
    create Rakefile
    create ticketing.gemspec
    create MIT-LICENSE
    create .gitignore
    create Gemfile
    create app
    create app/controllers/ticketing/application_controller.rb
    create app/helpers/ticketing/application_helper.rb
    create app/views/layouts/ticketing/application.html.erb
    create app/assets/images/ticketing
    create app/assets/images/ticketing/.gitkeep
    create config/routes.rb
    create lib/ticketing.rb
    create lib/tasks/ticketing_tasks.rake
    create lib/ticketing/version.rb
    create lib/ticketing/engine.rb
    create app/assets/stylesheets/ticketing/application.css
    create app/assets/javascripts/ticketing/application.js
    create script
    create script/rails
    create test/test_helper.rb
    create test/ticketing_test.rb
    append Rakefile
    create test/integration/navigation_test.rb
    vendor_app test/dummy

    View full-size slide

  59. create README.rdoc
    create Rakefile
    create ticketing.gemspec
    create MIT-LICENSE
    create .gitignore
    create Gemfile
    create app
    create app/controllers/ticketing/application_controller.rb
    create app/helpers/ticketing/application_helper.rb
    create app/views/layouts/ticketing/application.html.erb
    create app/assets/images/ticketing
    create app/assets/images/ticketing/.gitkeep
    create config/routes.rb
    create lib/ticketing.rb
    create lib/tasks/ticketing_tasks.rake
    create lib/ticketing/version.rb
    create lib/ticketing/engine.rb
    create app/assets/stylesheets/ticketing/application.css
    create app/assets/javascripts/ticketing/application.js
    create script
    create script/rails
    create test/test_helper.rb
    create test/ticketing_test.rb
    append Rakefile
    create test/integration/navigation_test.rb
    vendor_app test/dummy

    View full-size slide

  60. create README.rdoc
    create Rakefile
    create ticketing.gemspec
    create MIT-LICENSE
    create .gitignore
    create Gemfile
    create app
    create app/controllers/ticketing/application_controller.rb
    create app/helpers/ticketing/application_helper.rb
    create app/views/layouts/ticketing/application.html.erb
    create app/assets/images/ticketing
    create app/assets/images/ticketing/.gitkeep
    create config/routes.rb
    create lib/ticketing.rb
    create lib/tasks/ticketing_tasks.rake
    create lib/ticketing/version.rb
    create lib/ticketing/engine.rb
    create app/assets/stylesheets/ticketing/application.css
    create app/assets/javascripts/ticketing/application.js
    create script
    create script/rails
    create test/test_helper.rb
    create test/ticketing_test.rb
    append Rakefile
    create test/integration/navigation_test.rb
    vendor_app test/dummy

    View full-size slide

  61. create README.rdoc
    create Rakefile
    create ticketing.gemspec
    create MIT-LICENSE
    create .gitignore
    create Gemfile
    create app
    create app/controllers/ticketing/application_controller.rb
    create app/helpers/ticketing/application_helper.rb
    create app/views/layouts/ticketing/application.html.erb
    create app/assets/images/ticketing
    create app/assets/images/ticketing/.gitkeep
    create config/routes.rb
    create lib/ticketing.rb
    create lib/tasks/ticketing_tasks.rake
    create lib/ticketing/version.rb
    create lib/ticketing/engine.rb
    create app/assets/stylesheets/ticketing/application.css
    create app/assets/javascripts/ticketing/application.js
    create script
    create script/rails
    create test/test_helper.rb
    create test/ticketing_test.rb
    append Rakefile
    create test/integration/navigation_test.rb
    vendor_app test/dummy

    View full-size slide

  62. $ git push origin master

    View full-size slide

  63. gem  'ticketing',
           :git  =>  'git://path/to/my/git/repo.git'

    View full-size slide

  64. ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ...................................

    View full-size slide

  65. Lorem
    Ipsum
    Dolor
    Event
    Amet
    Consectetur
    Adipiscing
    Elit
    Vestibulum
    Lobortis
    DiscountCode
    Quis
    Est
    Gravida
    Posuere
    Aliquam
    Sit
    Amet
    Justo
    Leo
    In
    Facilisis
    Mi
    TicketType
    Diam
    Rutrum
    Vel
    Malesuada
    Ticket
    Dignissim

    View full-size slide

  66. Lorem
    Ipsum
    Dolor
    Event
    Amet
    Consectetur
    Adipiscing
    Elit
    Vestibulum
    Lobortis
    DiscountCode
    Quis
    Est
    Gravida
    Posuere
    Aliquam
    Sit
    Amet
    Justo
    Leo
    In
    Facilisis
    Mi
    TicketType
    Diam
    Rutrum
    Vel
    Malesuada
    Ticket
    Dignissim

    View full-size slide

  67. Lorem
    Ipsum
    Dolor
    Event
    Amet
    Consectetur
    Adipiscing
    Elit
    Vestibulum
    Lobortis
    DiscountCode
    Quis
    Est
    Gravida
    Posuere
    Aliquam
    Sit
    Amet
    Justo
    Leo
    In
    Facilisis
    Mi
    TicketType
    Diam
    Rutrum
    Vel
    Malesuada
    Ticket
    Dignissim

    View full-size slide

  68. Lorem
    Ipsum
    Dolor
    Event
    Amet
    Consectetur
    Adipiscing
    Elit
    Vestibulum
    Lobortis
    DiscountCode
    Quis
    Est
    Gravida
    Posuere
    Aliquam
    Sit
    Amet
    Justo
    Leo
    In
    Facilisis
    Mi
    TicketType
    Diam
    Rutrum
    Vel
    Malesuada
    Ticket
    Dignissim

    View full-size slide

  69. Lorem
    Ipsum
    Dolor
    Event
    Amet
    Consectetur
    Adipiscing
    Elit
    Vestibulum
    Lobortis
    DiscountCode
    Quis
    Est
    Gravida
    Posuere
    Aliquam
    Sit
    Amet
    Justo
    Leo
    In
    Facilisis
    Mi
    TicketType
    Diam
    Rutrum
    Vel
    Malesuada
    Ticket
    Dignissim

    View full-size slide

  70. main/app/models/event.rb
    main/app/models/discount_code.rb
    main/app/models/ticket_type.rb
    main/app/models/ticket.rb
    ticketing/app/models/event.rb
    ticketing/app/models/discount_code.rb
    ticketing/app/models/ticket_type.rb
    ticketing/app/models/ticket.rb

    View full-size slide

  71. ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ...................................

    View full-size slide

  72. main/spec/models/event_spec.rb
    main/spec/models/discount_code_spec.rb
    main/spec/models/ticket_type_spec.rb
    main/spec/models/ticket_spec.rb
    ticketing/spec/models/event_spec.rb
    ticketing/spec/models/discount_code_spec.rb
    ticketing/spec/models/ticket_type_spec.rb
    ticketing/spec/models/ticket_spec.rb

    View full-size slide

  73. ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................

    View full-size slide

  74. Muddied Boundaries

    View full-size slide

  75. Ticketing
    Main
    Invoicing
    User

    View full-size slide

  76. it  ‘can  determine  its  account  balance’  do
       #  Spec  here
    end

    View full-size slide

  77. Ticketing
    Main
    Invoicing
    User

    View full-size slide

  78. ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................

    View full-size slide

  79. ................................................
    ................................................
    ................................................
    ................................................

    View full-size slide

  80. Ticketing
    Main
    Invoicing
    User Invoice

    View full-size slide

  81. email
    encrypted_password
    password_salt
    reset_password_token
    remember_token
    remember_created_at
    sign_in_count
    current_sign_in_at
    last_sign_in_at
    current_sign_in_ip
    last_sign_in_ip
    confirmation_token
    confirmed_at
    confirmation_sent_at
    created_at
    updated_at
    billing_first_name
    billing_last_name
    authentication_token
    public_email
    address_street_and_premises
    address_city
    address_state_or_province
    address_postal_code
    phone_number
    billing_address_street_and_premises
    billing_address_city
    billing_address_state_or_province
    billing_address_postal_code
    billing_phone_number
    name
    logo
    description
    address_name
    billing_address_name

    View full-size slide

  82. Ticketing
    Main
    Invoicing
    User Invoice

    View full-size slide

  83. Ticketing
    Main
    Invoicing
    Invoice
    Account
    EventOrganizer
    User

    View full-size slide

  84. Ticketing
    Main
    Invoicing
    Invoice
    Event
    Organizer
    Account
    User

    View full-size slide

  85. ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................
    ................................................

    View full-size slide

  86. Invoicing
    Ticketing
    Main
    Invoice
    Event
    Organizer Account
    User

    View full-size slide

  87. email
    encrypted_password
    password_salt
    reset_password_token
    remember_token
    remember_created_at
    sign_in_count
    current_sign_in_at
    last_sign_in_at
    current_sign_in_ip
    last_sign_in_ip
    confirmation_token
    confirmed_at
    confirmation_sent_at
    created_at
    updated_at
    billing_first_name
    billing_last_name
    authentication_token
    public_email
    address_street_and_premises
    address_city
    address_state_or_province
    address_postal_code
    phone_number
    billing_address_street_and_premises
    billing_address_city
    billing_address_state_or_province
    billing_address_postal_code
    billing_phone_number
    name
    logo
    description
    address_name
    billing_address_name

    View full-size slide

  88. Creating the Interface

    View full-size slide

  89. class  TicketsController  <  ApplicationController
       #  Removed  code
       def  create
           event              =  Event.find(params[:event_id])
           ticket_type  =  TicketType.find(params[:ticket_type_id])
           params[:quantity].to_i.times  do
               #  Create  the  Ticket
               #  Apply  Discount  Codes
               #  Send  Emails
           end
           redirect_to  some_other_path
       end
       #  Removed  code
    end

    View full-size slide

  90. class  TicketsController  <  ApplicationController
       #  Removed  code
       def  create
           event              =  Event.find(params[:event_id])
           ticket_type  =  TicketType.find(params[:ticket_type_id])
           params[:quantity].to_i.times  do
               #  Create  the  Ticket
               #  Apply  Discount  Codes
               #  Send  Emails
           end
           redirect_to  some_other_path
       end
       #  Removed  code
    end

    View full-size slide

  91. class  TicketsController  <  ApplicationController
       #  Removed  code
       def  create
           event              =  Event.find(params[:event_id])
           ticket_type  =  TicketType.find(params[:ticket_type_id])
           params[:quantity].to_i.times  do
               #  Create  the  Ticket
               #  Apply  Discount  Codes
               #  Send  Emails
           end
           redirect_to  some_other_path
       end
       #  Removed  code
    end

    View full-size slide

  92. class  TicketsController  <  ApplicationController
       #  Removed  code
       def  create
           event              =  Event.find(params[:event_id])
           ticket_type  =  TicketType.find(params[:ticket_type_id])
           params[:quantity].to_i.times  do
               #  Create  the  Ticket
               #  Apply  Discount  Codes
               #  Send  Emails
           end
           redirect_to  some_other_path
       end
       #  Removed  code
    end

    View full-size slide

  93. class  TicketsController  <  ApplicationController
       #  Removed  code
       def  create
           event              =  Event.find(params[:event_id])
           ticket_type  =  TicketType.find(params[:ticket_type_id])
           params[:quantity].to_i.times  do
               #  Create  the  Ticket
               #  Apply  Discount  Codes
               #  Send  Emails
           end
           redirect_to  some_other_path
       end
       #  Removed  code
    end

    View full-size slide

  94. class  TicketsController  <  ApplicationController
       #  Removed  code
       def  create
           event              =  Event.find(params[:event_id])
           ticket_type  =  TicketType.find(params[:ticket_type_id])
           params[:quantity].to_i.times  do
               #  Create  the  Ticket
               #  Apply  Discount  Codes
               #  Send  Emails
           end
           redirect_to  some_other_path
       end
       #  Removed  code
    end

    View full-size slide

  95. class  TicketsController  <  ApplicationController
       #  Removed  code
       def  create
           BoxOffice.register_tickets(  type:                              params[:ticket_type_id]
                                                                   quantity:                      params[:quantity],
                                                                   send_notifications:  true)
           redirect_to  some_other_path
       end
       #  Removed  code
    end

    View full-size slide

  96. class  TicketsController  <  ApplicationController
       #  Removed  code
       def  create
           BoxOffice.register_tickets(  type:                              params[:ticket_type_id]
                                                                   quantity:                      params[:quantity],
                                                                   send_notifications:  true)
           redirect_to  some_other_path
       end
       #  Removed  code
    end

    View full-size slide

  97. class  TicketsController  <  ApplicationController
       #  Removed  code
       def  create
           BoxOffice.register_tickets(  type:                              params[:ticket_type_id]
                                                                   quantity:                      params[:quantity],
                                                                   send_notifications:  true)
           redirect_to  some_other_path
       end
       #  Removed  code
    end

    View full-size slide

  98. Progress Check

    View full-size slide

  99. Engines
    Gems
    Total Test Time: ~ 2.5 minutes
    Average Per-Gem Test Time: ~ 4 seconds

    View full-size slide

  100. Step 3: Profit

    View full-size slide

  101. Main
    Ticketing
    Invoicing
    User
    Ticketing
    Ticketing
    Load
    Balancer

    View full-size slide

  102. Image Credits
    https://secure.flickr.com/photos/lwr/168150955/in/photostream/
    http://alleverestnepal.files.wordpress.com/2011/07/everest-summit-view.jpg
    http://www.engineeringwellness.com/wp-content/uploads/2013/02/bigstock-Child-Listening-19669727.jpg
    http://www.parentspartner.com/wp-content/uploads/2011/05/angry-girl.jpg
    http://www.buriedwithchildren.com/wp-content/uploads/2010/02/DSCN3428.jpg
    http://fc08.deviantart.net/fs70/f/2012/038/2/d/1980__s___cartoon_a_gasim___by_timswit-d4p0eta.jpg
    http://www.pachd.com/free-images/household-images/20-dollar-bill-01.jpg
    http://cdn.madamenoire.com/wp-content/uploads/2011/10/Creepy-Guy.jpg
    http://images.wikia.com/lionking/images/c/c2/Simba_amazed.jpeg
    http://www.o5demo.com/userfiles/Aerial%20view4.jpg
    http://www.propstore.com/img/products/182/Waynes%20World_Garth%20Glasses.jpg
    https://kodequirks.files.wordpress.com/2010/05/fail.png?w=640
    http://www.hotforsecurity.com/wp-content/uploads/2013/01/ruby-on-rails-steams-critical-security-patch.jpg
    http://iphonewallpapers-hd.com/walls/travel_for_kids_mac_train_wallpapers_rail_trip-other.jpg
    https://images-na.ssl-images-amazon.com/images/G/01/dvd/lionsgate/Thomas2_lg.jpg
    http://www.vacationrentalmarketingblog.com/wp-content/uploads/2012/06/12969446611855980761do-not-symbol.jpg
    http://www.mostphotos.com/preview/389643/3d-ruby-gem-isolated.jpg
    http://thumbs.imagekind.com/member/3730ab28-65ec-4744-a89a-a36f0f6282bb/uploadedartwork/650X650/9c4774b8-b41a-4896-bef7-0c65ec7c9825.jpg
    http://www2.2space.net/images/upl_news/111017/386382/full/%26%23039%3Bsesame-street%26%23039%3B-back-online-after-porn-hacking.jpg
    https://www.library.qut.edu.au/blog/wp-content/uploads/2011/10/UN_flags_access_copy1.jpg
    http://www.hobbeslives.com/wp-content/uploads/2013/02/jigsaw-puzzle-2.jpg
    https://emilyrudisill.files.wordpress.com/2011/06/dsc04539.jpg
    https://lh3.ggpht.com/_WJjc0N1hIH4/S9ohkRZnDBI/AAAAAAAAK6M/0L-nWy8qsTs/s1600/old+ticket+stub.JPG
    http://theinsuranceblogger.co.uk/wp-content/uploads/2011/03/black-box.jpg
    http://raedevelopment.com/wp-content/uploads/2012/09/team-hands1.jpg
    https://krivstudiosblog.files.wordpress.com/2008/08/stephanie_michelle05.jpg
    http://zachandjody.com/blog/wp-content/uploads/2010/08/Kid-Stuffing-Face.jpg
    http://img1.etsystatic.com/005/1/6446101/il_fullxfull.383264621_3lm4.jpg
    http://www.whatsupyasieve.com/wp-content/uploads/2012/09/sad-panda.jpg
    http://remixacupuncture.com/wp-content/uploads/2013/05/ren-and-stimpy-1-745973.jpg
    https://lh3.ggpht.com/-uor9A9sz6xU/UZD4hwwnoEI/AAAAAAAAAnI/sXgYd4u946o/s1600/evildead2bdcap2_original.jpg
    https://lh3.ggpht.com/-L6z1kIIhPkc/T8wFQ_BdIDI/AAAAAAAABxU/42mDrQkAeqo/s1600/1%2Ba%2Ba%2Ba%2Btl%2Batirando.jpg
    http://michaelpiggott.files.wordpress.com/2012/12/thunder-buddies.jpg

    View full-size slide

  103. Thanks!
    Jeff Felchner
    @jfelchner

    View full-size slide