SlideShare uma empresa Scribd logo
1 de 38
Using and scaling
  Rack and Rack-based
               middleware
Alona Mekhovova
Ruby/Rails developer & co-founder @ RubyGarage

Organizer & coach @ RailsGirls

Ruby on Rails courses leading

Involved in growing Ruby Community in Dnipro

Monthly Rails MeetUps organizer


                                          skype: alony_
                                  alony@rubygarage.org
Overview
Why do we need Rack?

Simple Rack app & own middleware

Available middleware overview

Plugging middleware into Rails

What’s next?
Lots of Web-servers
...and frameworks
the http protocol
request => response

stateless
request:               response:
Request method, URI,   Protocol version,
protocol version       status code, its desc

Request headers        Response headers

Request body           Response body
http
from a bird’s eye view

REQUEST         RESPONSE
Request structure
{"HTTP_USER_AGENT"=>"curl/7.12.2 ..."      Classically, a
 "REMOTE_HOST"=>"127.0.0.1",               CGI
 "PATH_INFO"=>"/",
 "HTTP_HOST"=>"ruby-lang.org",             environment
 "SERVER_PROTOCOL"=>"HTTP/1.1",
 "SCRIPT_NAME"=>"",
 "REQUEST_PATH"=>"/",
                                           Most
 "REMOTE_ADDR"=>"127.0.0.1",               frameworks
 "HTTP_VERSION"=>"HTTP/1.1",
 "REQUEST_URI"=>"http://ruby-lang.org/",
                                           already use
 "SERVER_PORT"=>"80",                      smth like that,
 "HTTP_PRAGMA"=>"no-cache",                most developers
 "QUERY_STRING"=>"",
 "GATEWAY_INTERFACE"=>"CGI/1.1",           know the fields
 "HTTP_ACCEPT"=>"*/*",
 "REQUEST_METHOD"=>"GET"}
                                           Let’s keep it
Response structure
 Status   HTTP/1.1 302 Found
          Date: Sat, 27 Oct 2007 10:07:53 GMT
          Server: Apache/2.0.54 (Debian GNU/Linux)
          mod_ssl/2.0.54 OpenSSL0.9.7e

Headers   Location: http://www.ruby-lang.org/
          Content-Length: 209
          Content-Type: text/html; charset=iso-8859-1

  Body    <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
          <html><head>
          <title>302 Found</title>
          </head><body>
          <h1>Found</h1>
          <p>The document has moved <a
          href="http://www.ruby-lang.org/">here</a>
          </p>
          </body></html>
Response in Ruby
  Status   HTTP/1.1 302 Found
Integer    Date: Sat, 27 Oct 2007 10:07:53 GMT
           Server: Apache/2.0.54 (Debian GNU/Linux)
           mod_ssl/2.0.54 OpenSSL0.9.7e

Headers    Location: http://www.ruby-lang.org/
           Content-Length: 209
  Hash     Content-Type: text/html; charset=iso-8859-1

  Body     <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
 Array     <html><head>
           <title>302 Found</title>
           </head><body>
           <h1>Found</h1>
           <p>The document has moved <a
           href="http://www.ruby-lang.org/">here</a>
           </p>
           </body></html>
Response in Ruby
                   Environment
                                    Status
lambda { |env|
         [
           200,
           {"Content-Type"=>"text/plain"},
           ["Hello, Rack!"]
         ]
       }                                 Headers


                        Body
Summarizing

The Rack app gets called with the CGI
environment...

...and returns an Array of status, header & body
...and again


 HTTP SERVER   YOUR FANCY APP
Simplest Rack app
run Proc.new { |env|
         [
           200,
           {"Content-Type"=>"text/plain"},
           ["Hello, Rack!"]
         ]
       }
rackup
# config.ru

class Awesome
 def call(env)
   [200, {'Content-Type' => 'text/plain'}, 'AWESOME.']
 end
end

run Awesome.new


# console

rackup config.ru
Rack::Builder
app = Rack::Builder.app do
  map '/awesome' do
    run Awesome
  end
  
  map '/' do
    run Proc{ 404,
        {"Content-Type" => "text/html"},
        ['awesome requests only'] }
  end
end

run app
Rack::Builder

Rack::Builder.new do
  use Rack::CommonLogger
  use Rack::ShowExceptions
  use Rack::ShowStatus
  use Rack::Lint
  run MyRackApp.new
end
Middleware
    HTTP                    HTTP

 Middleware1             Middleware

 Middleware2
                     Rack          Rack
                   application   application
Rack application
Home-made middleware
class JSMinifier
    
  def initialize(app, path)
    @app, @root = app, File.expand_path(path)
  end

  def call(env)
    path = File.join(@root, Utils.unescape(env["PATH_INFO"]))
    return @app.call(env) unless path.match(/.*/(w+.js)$/)
 
    if !File.readable?(path) or env["PATH_INFO"].include?("..")
      return [403, {"Content-Type" => "text/plain"}, ["Forbiddenn"]]
    end

    return [ 200,
             { "Content-Type" => "text/javascript" },
             [JSMin.minify( File.new( path, "r" ) )]
           ]
  end
end
Home-made middleware
class JSMinifier
    
  def initialize(app, path)
    @app, @root = app, File.expand_path(path)
  end

  def call(env)
    path = File.join(@root, Utils.unescape(env["PATH_INFO"]))
    return @app.call(env) unless path.match(/.*/(w+.js)$/)
 
    if !File.readable?(path) or env["PATH_INFO"].include?("..")
      return [403, {"Content-Type" => "text/plain"}, ["Forbiddenn"]]
    end

    return [ 200,
             { "Content-Type" => "text/javascript" },
             [JSMin.minify( File.new( path, "r" ) )]
           ]
  end
end
Home-made middleware
class JSMinifier
    
  def initialize(app, path)
    @app, @root = app, File.expand_path(path)
  end

  def call(env)
    path = File.join(@root, Utils.unescape(env["PATH_INFO"]))
    return @app.call(env) unless path.match(/.*/(w+.js)$/)
 
    if !File.readable?(path) or env["PATH_INFO"].include?("..")
      return [403, {"Content-Type" => "text/plain"}, ["Forbiddenn"]]
    end

    return [ 200,
             { "Content-Type" => "text/javascript" },
             [JSMin.minify( File.new( path, "r" ) )]
           ]
  end
end
What we already have
Rack::Bug
Rack::Cascade
Rack::Cache
Rack::GeoIP
Rack::Callback
Rack::MailExceptions
Rack::Honeypot
env['warden'].authenticated?
     env['warden'].authenticate!(:password)
     env['warden'].user


     Warden::Strategies.add(:password) do

       def valid?
         params[:username] || params[:password]
       end

       def authenticate!
         u = User.authenticate(params[:username],
     params[:password])
         u.nil? ? fail!("Could not log in") : success!
     (u)
       end
     end



Warden
... and lots of others
 Rack::Static             Rack::CSSHTTPRequest

     Rack::noIE                 Rack::GoogleAnalytics

          Rack::Profiler              Rack::Maintenance

Rack::Lock        Rack::Spellcheck          Rack::Log

             Rack::Pack              Rack::Validate

   https://github.com/rack/rack/wiki/List-of-Middleware
              http://coderack.org/middlewares
Plug it into Rails stack
$ rake middleware

use   ActionDispatch::Static
use   Rack::Lock
use   ActiveSupport::Cache::Strategy::LocalCache
use   Rack::Runtime
use   Rails::Rack::Logger
use   ActionDispatch::ShowExceptions
use   ActionDispatch::DebugExceptions
use   ActionDispatch::RemoteIp
use   Rack::Sendfile
use   ActionDispatch::Callbacks
use   ActiveRecord::ConnectionAdapters::ConnectionManagement
use   ActiveRecord::QueryCache
      ...
use   Rack::MethodOverride
use   ActionDispatch::Head
use   ActionDispatch::BestStandardsSupport
run   MyApp::Application.routes
Configure middleware stack
Rails::Initializer.run do |config|
  config.middleware.use Rack::MailExceptions
  config.middleware.delete Rack::Lock
  config.middleware.insert_after Rack::Sendfile, Rack::Static
  config.middleware.insert_before Rack::Head, Ben::Asplode
  config.middleware.swap ActionDispatch::Callbacks,
ActiveRecord::QueryCache
end




        config.middleware.is_a? Array   # => true
...or replace it
# config/initializers/stack.rb
ActionController::Dispatcher.middleware =
       ActionController::MiddlewareStack.new do |m|
         m.use ActionController::Failsafe
         m.use ActiveRecord::QueryCache
         m.use Rack::Head
end


        # console
        $ rake middleware

        use   ActionController::Failsafe
        use   ActiveRecord::QueryCache
        use   Rack::Head
        run   ActionController::Dispatcher.new
The future
Rails 4 will have an API only middleware stack
configuration

RocketPants is an interesting alternative right now
(github.com/filtersquad/rocket_pants)
Many thanks!

Mais conteúdo relacionado

Mais procurados

Construindo APIs Usando Rails
Construindo APIs Usando RailsConstruindo APIs Usando Rails
Construindo APIs Usando RailsFernando Kakimoto
 
Apache Hive Hook
Apache Hive HookApache Hive Hook
Apache Hive HookMinwoo Kim
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Racksickill
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Elena Kolevska
 
HTTP Caching and PHP
HTTP Caching and PHPHTTP Caching and PHP
HTTP Caching and PHPDavid de Boer
 
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...Puppet
 
Rails 2.0 Presentation
Rails 2.0 PresentationRails 2.0 Presentation
Rails 2.0 PresentationScott Chacon
 
Hashiconf EU 2019 - A Tour of Terraform 0.12
Hashiconf EU 2019 - A Tour of Terraform 0.12Hashiconf EU 2019 - A Tour of Terraform 0.12
Hashiconf EU 2019 - A Tour of Terraform 0.12Mitchell Pronschinske
 
HBaseConEast2016: HBase on Docker with Clusterdock
HBaseConEast2016: HBase on Docker with ClusterdockHBaseConEast2016: HBase on Docker with Clusterdock
HBaseConEast2016: HBase on Docker with ClusterdockMichael Stack
 
Real time server
Real time serverReal time server
Real time serverthepian
 
Failsafe Mechanism for Yahoo Homepage
Failsafe Mechanism for Yahoo HomepageFailsafe Mechanism for Yahoo Homepage
Failsafe Mechanism for Yahoo HomepageKit Chan
 
REST APIs in Laravel 101
REST APIs in Laravel 101REST APIs in Laravel 101
REST APIs in Laravel 101Samantha Geitz
 
Deploy Rails Application by Capistrano
Deploy Rails Application by CapistranoDeploy Rails Application by Capistrano
Deploy Rails Application by CapistranoTasawr Interactive
 
Replacing Squid with ATS
Replacing Squid with ATSReplacing Squid with ATS
Replacing Squid with ATSKit Chan
 

Mais procurados (20)

Rack
RackRack
Rack
 
Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 
Construindo APIs Usando Rails
Construindo APIs Usando RailsConstruindo APIs Usando Rails
Construindo APIs Usando Rails
 
Apache Hive Hook
Apache Hive HookApache Hive Hook
Apache Hive Hook
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
Refactoring terraform
Refactoring terraformRefactoring terraform
Refactoring terraform
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
HTTP Caching and PHP
HTTP Caching and PHPHTTP Caching and PHP
HTTP Caching and PHP
 
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
 
5-WebServers.ppt
5-WebServers.ppt5-WebServers.ppt
5-WebServers.ppt
 
Frontend Servers and NGINX: What, Where and How
Frontend Servers and NGINX: What, Where and HowFrontend Servers and NGINX: What, Where and How
Frontend Servers and NGINX: What, Where and How
 
Rails 2.0 Presentation
Rails 2.0 PresentationRails 2.0 Presentation
Rails 2.0 Presentation
 
Hashiconf EU 2019 - A Tour of Terraform 0.12
Hashiconf EU 2019 - A Tour of Terraform 0.12Hashiconf EU 2019 - A Tour of Terraform 0.12
Hashiconf EU 2019 - A Tour of Terraform 0.12
 
HBaseConEast2016: HBase on Docker with Clusterdock
HBaseConEast2016: HBase on Docker with ClusterdockHBaseConEast2016: HBase on Docker with Clusterdock
HBaseConEast2016: HBase on Docker with Clusterdock
 
Real time server
Real time serverReal time server
Real time server
 
Failsafe Mechanism for Yahoo Homepage
Failsafe Mechanism for Yahoo HomepageFailsafe Mechanism for Yahoo Homepage
Failsafe Mechanism for Yahoo Homepage
 
REST APIs in Laravel 101
REST APIs in Laravel 101REST APIs in Laravel 101
REST APIs in Laravel 101
 
Server Side? Swift
Server Side? SwiftServer Side? Swift
Server Side? Swift
 
Deploy Rails Application by Capistrano
Deploy Rails Application by CapistranoDeploy Rails Application by Capistrano
Deploy Rails Application by Capistrano
 
Replacing Squid with ATS
Replacing Squid with ATSReplacing Squid with ATS
Replacing Squid with ATS
 

Destaque

Rapid-ruby-api-on-grape
Rapid-ruby-api-on-grapeRapid-ruby-api-on-grape
Rapid-ruby-api-on-grapeAndy Wang
 
The archived Canadian US Patent Competitive Intelligence Database (2016/6/28)
The archived Canadian US Patent Competitive Intelligence Database (2016/6/28) The archived Canadian US Patent Competitive Intelligence Database (2016/6/28)
The archived Canadian US Patent Competitive Intelligence Database (2016/6/28) Muchiu (Henry) Chang, PhD. Cantab
 
The Archived Canadian Patent Competitive Intelligence (January 11, 2011)
The Archived Canadian Patent Competitive Intelligence (January 11, 2011)The Archived Canadian Patent Competitive Intelligence (January 11, 2011)
The Archived Canadian Patent Competitive Intelligence (January 11, 2011)Muchiu (Henry) Chang, PhD. Cantab
 
Search Engine Optimisation - Have you been crawled over?
Search Engine Optimisation - Have you been crawled over?Search Engine Optimisation - Have you been crawled over?
Search Engine Optimisation - Have you been crawled over?Marshal Yung
 
The archived Canadian US Patent Competitive Intelligence Database (2014/7/22)
The archived Canadian US Patent Competitive Intelligence Database (2014/7/22) The archived Canadian US Patent Competitive Intelligence Database (2014/7/22)
The archived Canadian US Patent Competitive Intelligence Database (2014/7/22) Muchiu (Henry) Chang, PhD. Cantab
 
The archived Canadian US Patent Competitive Intelligence Database (2015/8/25)
The archived Canadian US Patent Competitive Intelligence Database (2015/8/25) The archived Canadian US Patent Competitive Intelligence Database (2015/8/25)
The archived Canadian US Patent Competitive Intelligence Database (2015/8/25) Muchiu (Henry) Chang, PhD. Cantab
 
4th yr images
4th yr images4th yr images
4th yr imageskaziomer
 
Hubspot Charts Graphs April2010
Hubspot Charts Graphs April2010Hubspot Charts Graphs April2010
Hubspot Charts Graphs April2010SocialOnline
 
Verrex E Portfolio 2011
Verrex E Portfolio 2011Verrex E Portfolio 2011
Verrex E Portfolio 2011wchivil
 
The archived Canadian US Patent Competitive Intelligence Database (2016/3/8)
The archived Canadian US Patent Competitive Intelligence Database (2016/3/8) The archived Canadian US Patent Competitive Intelligence Database (2016/3/8)
The archived Canadian US Patent Competitive Intelligence Database (2016/3/8) Muchiu (Henry) Chang, PhD. Cantab
 
The Archived Canadian Patent Competitive Intelligence (May 3, 2011)
The Archived Canadian Patent Competitive Intelligence (May 3, 2011)The Archived Canadian Patent Competitive Intelligence (May 3, 2011)
The Archived Canadian Patent Competitive Intelligence (May 3, 2011)Muchiu (Henry) Chang, PhD. Cantab
 
Timing-pulse measurement and detector calibration for the OsteoQuant®.
Timing-pulse measurement and detector calibration for the OsteoQuant®.Timing-pulse measurement and detector calibration for the OsteoQuant®.
Timing-pulse measurement and detector calibration for the OsteoQuant®.Binu Enchakalody
 
The Archived Canadian Patent Competitive Intelligence (2013/10/8)
The Archived Canadian Patent Competitive Intelligence (2013/10/8) The Archived Canadian Patent Competitive Intelligence (2013/10/8)
The Archived Canadian Patent Competitive Intelligence (2013/10/8) Muchiu (Henry) Chang, PhD. Cantab
 
The archived Canadian Competitive Intelligence (CI) by Patent Mapping, August...
The archived Canadian Competitive Intelligence (CI) by Patent Mapping, August...The archived Canadian Competitive Intelligence (CI) by Patent Mapping, August...
The archived Canadian Competitive Intelligence (CI) by Patent Mapping, August...Muchiu (Henry) Chang, PhD. Cantab
 
The archived Canadian US Patent Competitive Intelligence Database (2015/7/28)
The archived Canadian US Patent Competitive Intelligence Database (2015/7/28) The archived Canadian US Patent Competitive Intelligence Database (2015/7/28)
The archived Canadian US Patent Competitive Intelligence Database (2015/7/28) Muchiu (Henry) Chang, PhD. Cantab
 
The archived Canadian US Patent Competitive Intelligence Database (2015/6/9)
The archived Canadian US Patent Competitive Intelligence Database (2015/6/9) The archived Canadian US Patent Competitive Intelligence Database (2015/6/9)
The archived Canadian US Patent Competitive Intelligence Database (2015/6/9) Muchiu (Henry) Chang, PhD. Cantab
 
The archived Canadian US Patent Competitive Intelligence Database (2015/8/11)
The archived Canadian US Patent Competitive Intelligence Database (2015/8/11) The archived Canadian US Patent Competitive Intelligence Database (2015/8/11)
The archived Canadian US Patent Competitive Intelligence Database (2015/8/11) Muchiu (Henry) Chang, PhD. Cantab
 

Destaque (20)

Rapid-ruby-api-on-grape
Rapid-ruby-api-on-grapeRapid-ruby-api-on-grape
Rapid-ruby-api-on-grape
 
The archived Canadian US Patent Competitive Intelligence Database (2016/6/28)
The archived Canadian US Patent Competitive Intelligence Database (2016/6/28) The archived Canadian US Patent Competitive Intelligence Database (2016/6/28)
The archived Canadian US Patent Competitive Intelligence Database (2016/6/28)
 
Ti
TiTi
Ti
 
The Archived Canadian Patent Competitive Intelligence (January 11, 2011)
The Archived Canadian Patent Competitive Intelligence (January 11, 2011)The Archived Canadian Patent Competitive Intelligence (January 11, 2011)
The Archived Canadian Patent Competitive Intelligence (January 11, 2011)
 
Search Engine Optimisation - Have you been crawled over?
Search Engine Optimisation - Have you been crawled over?Search Engine Optimisation - Have you been crawled over?
Search Engine Optimisation - Have you been crawled over?
 
The archived Canadian US Patent Competitive Intelligence Database (2014/7/22)
The archived Canadian US Patent Competitive Intelligence Database (2014/7/22) The archived Canadian US Patent Competitive Intelligence Database (2014/7/22)
The archived Canadian US Patent Competitive Intelligence Database (2014/7/22)
 
The archived Canadian US Patent Competitive Intelligence Database (2015/8/25)
The archived Canadian US Patent Competitive Intelligence Database (2015/8/25) The archived Canadian US Patent Competitive Intelligence Database (2015/8/25)
The archived Canadian US Patent Competitive Intelligence Database (2015/8/25)
 
A Feast for Your Eyes
A Feast for Your EyesA Feast for Your Eyes
A Feast for Your Eyes
 
4th yr images
4th yr images4th yr images
4th yr images
 
Hubspot Charts Graphs April2010
Hubspot Charts Graphs April2010Hubspot Charts Graphs April2010
Hubspot Charts Graphs April2010
 
Verrex E Portfolio 2011
Verrex E Portfolio 2011Verrex E Portfolio 2011
Verrex E Portfolio 2011
 
The archived Canadian US Patent Competitive Intelligence Database (2016/3/8)
The archived Canadian US Patent Competitive Intelligence Database (2016/3/8) The archived Canadian US Patent Competitive Intelligence Database (2016/3/8)
The archived Canadian US Patent Competitive Intelligence Database (2016/3/8)
 
The Archived Canadian Patent Competitive Intelligence (May 3, 2011)
The Archived Canadian Patent Competitive Intelligence (May 3, 2011)The Archived Canadian Patent Competitive Intelligence (May 3, 2011)
The Archived Canadian Patent Competitive Intelligence (May 3, 2011)
 
Timing-pulse measurement and detector calibration for the OsteoQuant®.
Timing-pulse measurement and detector calibration for the OsteoQuant®.Timing-pulse measurement and detector calibration for the OsteoQuant®.
Timing-pulse measurement and detector calibration for the OsteoQuant®.
 
Ado Net
Ado NetAdo Net
Ado Net
 
The Archived Canadian Patent Competitive Intelligence (2013/10/8)
The Archived Canadian Patent Competitive Intelligence (2013/10/8) The Archived Canadian Patent Competitive Intelligence (2013/10/8)
The Archived Canadian Patent Competitive Intelligence (2013/10/8)
 
The archived Canadian Competitive Intelligence (CI) by Patent Mapping, August...
The archived Canadian Competitive Intelligence (CI) by Patent Mapping, August...The archived Canadian Competitive Intelligence (CI) by Patent Mapping, August...
The archived Canadian Competitive Intelligence (CI) by Patent Mapping, August...
 
The archived Canadian US Patent Competitive Intelligence Database (2015/7/28)
The archived Canadian US Patent Competitive Intelligence Database (2015/7/28) The archived Canadian US Patent Competitive Intelligence Database (2015/7/28)
The archived Canadian US Patent Competitive Intelligence Database (2015/7/28)
 
The archived Canadian US Patent Competitive Intelligence Database (2015/6/9)
The archived Canadian US Patent Competitive Intelligence Database (2015/6/9) The archived Canadian US Patent Competitive Intelligence Database (2015/6/9)
The archived Canadian US Patent Competitive Intelligence Database (2015/6/9)
 
The archived Canadian US Patent Competitive Intelligence Database (2015/8/11)
The archived Canadian US Patent Competitive Intelligence Database (2015/8/11) The archived Canadian US Patent Competitive Intelligence Database (2015/8/11)
The archived Canadian US Patent Competitive Intelligence Database (2015/8/11)
 

Semelhante a Using and scaling Rack and Rack-based middleware

Ruby MVC from scratch with Rack
Ruby MVC from scratch with RackRuby MVC from scratch with Rack
Ruby MVC from scratch with RackDonSchado
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to TornadoGavin Roy
 
Apache and PHP: Why httpd.conf is your new BFF!
Apache and PHP: Why httpd.conf is your new BFF!Apache and PHP: Why httpd.conf is your new BFF!
Apache and PHP: Why httpd.conf is your new BFF!Jeff Jones
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryTatsuhiko Miyagawa
 
Adriano Di Luzio - Davvy - PyconSEI Talk
Adriano Di Luzio - Davvy - PyconSEI TalkAdriano Di Luzio - Davvy - PyconSEI Talk
Adriano Di Luzio - Davvy - PyconSEI Talkaldur999
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortalJennifer Bourey
 
Scalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSScalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSCosmin Mereuta
 
nodejs_at_a_glance.ppt
nodejs_at_a_glance.pptnodejs_at_a_glance.ppt
nodejs_at_a_glance.pptWalaSidhom1
 
Play Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and ScalaPlay Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and ScalaYevgeniy Brikman
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディングXitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディングscalaconfjp
 
Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014Ngoc Dao
 
Express Presentation
Express PresentationExpress Presentation
Express Presentationaaronheckmann
 
Scalalable Language for a Scalable Web
Scalalable Language for a Scalable WebScalalable Language for a Scalable Web
Scalalable Language for a Scalable WebTimothy Perrett
 
Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018Adam Tomat
 
Universal JavaScript
Universal JavaScriptUniversal JavaScript
Universal JavaScript名辰 洪
 

Semelhante a Using and scaling Rack and Rack-based middleware (20)

Intro to Rack
Intro to RackIntro to Rack
Intro to Rack
 
Ruby MVC from scratch with Rack
Ruby MVC from scratch with RackRuby MVC from scratch with Rack
Ruby MVC from scratch with Rack
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to Tornado
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
Apache and PHP: Why httpd.conf is your new BFF!
Apache and PHP: Why httpd.conf is your new BFF!Apache and PHP: Why httpd.conf is your new BFF!
Apache and PHP: Why httpd.conf is your new BFF!
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Adriano Di Luzio - Davvy - PyconSEI Talk
Adriano Di Luzio - Davvy - PyconSEI TalkAdriano Di Luzio - Davvy - PyconSEI Talk
Adriano Di Luzio - Davvy - PyconSEI Talk
 
Plack at YAPC::NA 2010
Plack at YAPC::NA 2010Plack at YAPC::NA 2010
Plack at YAPC::NA 2010
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortal
 
Scalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSScalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JS
 
nodejs_at_a_glance.ppt
nodejs_at_a_glance.pptnodejs_at_a_glance.ppt
nodejs_at_a_glance.ppt
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
Play Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and ScalaPlay Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and Scala
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディングXitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
 
Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014
 
Express Presentation
Express PresentationExpress Presentation
Express Presentation
 
Scalalable Language for a Scalable Web
Scalalable Language for a Scalable WebScalalable Language for a Scalable Web
Scalalable Language for a Scalable Web
 
Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018
 
Universal JavaScript
Universal JavaScriptUniversal JavaScript
Universal JavaScript
 

Último

Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
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
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
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
 
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
 
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
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
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
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 

Último (20)

Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
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
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
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
 
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
 
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...
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
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
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 

Using and scaling Rack and Rack-based middleware

  • 1. Using and scaling Rack and Rack-based middleware
  • 2. Alona Mekhovova Ruby/Rails developer & co-founder @ RubyGarage Organizer & coach @ RailsGirls Ruby on Rails courses leading Involved in growing Ruby Community in Dnipro Monthly Rails MeetUps organizer skype: alony_ alony@rubygarage.org
  • 3. Overview Why do we need Rack? Simple Rack app & own middleware Available middleware overview Plugging middleware into Rails What’s next?
  • 4.
  • 7. the http protocol request => response stateless
  • 8. request: response: Request method, URI, Protocol version, protocol version status code, its desc Request headers Response headers Request body Response body
  • 9. http from a bird’s eye view REQUEST RESPONSE
  • 10. Request structure {"HTTP_USER_AGENT"=>"curl/7.12.2 ..." Classically, a "REMOTE_HOST"=>"127.0.0.1", CGI "PATH_INFO"=>"/", "HTTP_HOST"=>"ruby-lang.org", environment "SERVER_PROTOCOL"=>"HTTP/1.1", "SCRIPT_NAME"=>"", "REQUEST_PATH"=>"/", Most "REMOTE_ADDR"=>"127.0.0.1", frameworks "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_URI"=>"http://ruby-lang.org/", already use "SERVER_PORT"=>"80", smth like that, "HTTP_PRAGMA"=>"no-cache", most developers "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1", know the fields "HTTP_ACCEPT"=>"*/*", "REQUEST_METHOD"=>"GET"} Let’s keep it
  • 11. Response structure Status HTTP/1.1 302 Found Date: Sat, 27 Oct 2007 10:07:53 GMT Server: Apache/2.0.54 (Debian GNU/Linux) mod_ssl/2.0.54 OpenSSL0.9.7e Headers Location: http://www.ruby-lang.org/ Content-Length: 209 Content-Type: text/html; charset=iso-8859-1 Body <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>302 Found</title> </head><body> <h1>Found</h1> <p>The document has moved <a href="http://www.ruby-lang.org/">here</a> </p> </body></html>
  • 12. Response in Ruby Status HTTP/1.1 302 Found Integer Date: Sat, 27 Oct 2007 10:07:53 GMT Server: Apache/2.0.54 (Debian GNU/Linux) mod_ssl/2.0.54 OpenSSL0.9.7e Headers Location: http://www.ruby-lang.org/ Content-Length: 209 Hash Content-Type: text/html; charset=iso-8859-1 Body <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> Array <html><head> <title>302 Found</title> </head><body> <h1>Found</h1> <p>The document has moved <a href="http://www.ruby-lang.org/">here</a> </p> </body></html>
  • 13. Response in Ruby Environment Status lambda { |env|     [        200,        {"Content-Type"=>"text/plain"},        ["Hello, Rack!"]      ]    } Headers Body
  • 14. Summarizing The Rack app gets called with the CGI environment... ...and returns an Array of status, header & body
  • 15. ...and again HTTP SERVER YOUR FANCY APP
  • 16. Simplest Rack app run Proc.new { |env|     [        200,        {"Content-Type"=>"text/plain"},        ["Hello, Rack!"]      ]    }
  • 17. rackup # config.ru class Awesome def call(env) [200, {'Content-Type' => 'text/plain'}, 'AWESOME.'] end end run Awesome.new # console rackup config.ru
  • 18. Rack::Builder app = Rack::Builder.app do   map '/awesome' do     run Awesome   end      map '/' do     run Proc{ 404, {"Content-Type" => "text/html"}, ['awesome requests only'] }   end end run app
  • 19. Rack::Builder Rack::Builder.new do   use Rack::CommonLogger   use Rack::ShowExceptions   use Rack::ShowStatus   use Rack::Lint   run MyRackApp.new end
  • 20. Middleware HTTP HTTP Middleware1 Middleware Middleware2 Rack Rack application application Rack application
  • 21. Home-made middleware class JSMinifier      def initialize(app, path)     @app, @root = app, File.expand_path(path)   end   def call(env)     path = File.join(@root, Utils.unescape(env["PATH_INFO"]))     return @app.call(env) unless path.match(/.*/(w+.js)$/)       if !File.readable?(path) or env["PATH_INFO"].include?("..")       return [403, {"Content-Type" => "text/plain"}, ["Forbiddenn"]]     end     return [ 200,        { "Content-Type" => "text/javascript" },        [JSMin.minify( File.new( path, "r" ) )]      ]   end end
  • 22. Home-made middleware class JSMinifier      def initialize(app, path)     @app, @root = app, File.expand_path(path)   end   def call(env)     path = File.join(@root, Utils.unescape(env["PATH_INFO"]))     return @app.call(env) unless path.match(/.*/(w+.js)$/)       if !File.readable?(path) or env["PATH_INFO"].include?("..")       return [403, {"Content-Type" => "text/plain"}, ["Forbiddenn"]]     end     return [ 200,        { "Content-Type" => "text/javascript" },        [JSMin.minify( File.new( path, "r" ) )]      ]   end end
  • 23. Home-made middleware class JSMinifier      def initialize(app, path)     @app, @root = app, File.expand_path(path)   end   def call(env)     path = File.join(@root, Utils.unescape(env["PATH_INFO"]))     return @app.call(env) unless path.match(/.*/(w+.js)$/)       if !File.readable?(path) or env["PATH_INFO"].include?("..")       return [403, {"Content-Type" => "text/plain"}, ["Forbiddenn"]]     end     return [ 200,        { "Content-Type" => "text/javascript" },        [JSMin.minify( File.new( path, "r" ) )]      ]   end end
  • 32. env['warden'].authenticated? env['warden'].authenticate!(:password) env['warden'].user Warden::Strategies.add(:password) do   def valid?     params[:username] || params[:password]   end   def authenticate!     u = User.authenticate(params[:username], params[:password])     u.nil? ? fail!("Could not log in") : success! (u)   end end Warden
  • 33. ... and lots of others Rack::Static Rack::CSSHTTPRequest Rack::noIE Rack::GoogleAnalytics Rack::Profiler Rack::Maintenance Rack::Lock Rack::Spellcheck Rack::Log Rack::Pack Rack::Validate https://github.com/rack/rack/wiki/List-of-Middleware http://coderack.org/middlewares
  • 34. Plug it into Rails stack $ rake middleware use ActionDispatch::Static use Rack::Lock use ActiveSupport::Cache::Strategy::LocalCache use Rack::Runtime use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::DebugExceptions use ActionDispatch::RemoteIp use Rack::Sendfile use ActionDispatch::Callbacks use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache ... use Rack::MethodOverride use ActionDispatch::Head use ActionDispatch::BestStandardsSupport run MyApp::Application.routes
  • 35. Configure middleware stack Rails::Initializer.run do |config|   config.middleware.use Rack::MailExceptions   config.middleware.delete Rack::Lock   config.middleware.insert_after Rack::Sendfile, Rack::Static   config.middleware.insert_before Rack::Head, Ben::Asplode   config.middleware.swap ActionDispatch::Callbacks, ActiveRecord::QueryCache end config.middleware.is_a? Array # => true
  • 36. ...or replace it # config/initializers/stack.rb ActionController::Dispatcher.middleware = ActionController::MiddlewareStack.new do |m|    m.use ActionController::Failsafe    m.use ActiveRecord::QueryCache    m.use Rack::Head end # console $ rake middleware use ActionController::Failsafe use ActiveRecord::QueryCache use Rack::Head run ActionController::Dispatcher.new
  • 37. The future Rails 4 will have an API only middleware stack configuration RocketPants is an interesting alternative right now (github.com/filtersquad/rocket_pants)

Notas do Editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n