SlideShare une entreprise Scribd logo
1  sur  59
Deploy JRuby on Rails to Windows Server 2008 R2
About Me

•         (Lu Wei Jen)

•
    • http://www.handlino.com
• Facebook: http://www.facebook.com/weijenlu
• Twitter: weijenlu
Agenda

• Why Windows
• Why JRuby
• Using Java’s Resources
• JRoR on Windows Environment
• Deployment
Why Windows
It’s All About Money
Q1 2010 units                               Q1 2010 dollars

Windows 1,379,487 (75.3%)                   Windows $5.1 billion (48.9%)
Unix       65,451 (3.6%)                    Unix    $2.3 billion (22.2%)
Linux    380,429 (20.8%)                    Linux   $1.7 billion (16.2%)


Q4 2009 units                               Q4 2009 dollars
Windows 1,434,225 (73.9%)                   Windows $5.4 billion (41.6%)
Unix        84,851 ( 4.4%)                  Unix    $3.9 billion (29.9%)
Linux      412,041 (21.2%)                  Linux   $1.9 billion (14.7%)




 http://www.zdnet.com/blog/microsoft/idc-windows-server-still-rules-the-server-roost/6424
More Jobs
More Jobs

More Rubiest
More Jobs

 More Rubiest

More Resources
More Jobs

 More Rubiest

More Resources

 More Money
Why JRuby

• You can use java resources.
• More easy to deploy to Windows.
• True multithreading.
• JRuby is just a .jar file.
          http://bit.ly/cPNg9f
Using Java Resources
Wrapping a Library(1)
require 'java'

# create objects
pdf = com.itextpdf.text.Document.new
para =
com.itextpdf.text.Paragraph.new
'Using Java resources from JRuby'
file = java.io.FileOutputStream.new
'pdf_demo.pdf'
                 https://gist.github.com/e4b1d813394e58188e59
Wrapping a Library(2)
# get_instance is an alias for
getInstance
com.itextpdf.text.pdf.PdfWriter.
get_instance(pdf, file)

pdf.open
pdf.add para
pdf.close

               https://gist.github.com/e4b1d813394e58188e59
Wrapping a Library(3)


• Run
 • jruby -J-cp itextpdf-5.1.2.jar pdf_demo.rb
Classpath(1)

• Environment Variable
 • set RUBYOPT=-IC:jrubyitext
 • set CLASSPATH=%CLASSPATH%C:jruby
   itext
Classpath(2)
require 'java'
require 'itextpdf-5.1.2.jar'

pdf=com.itextpdf.text.Document.new
        ...



               https://gist.github.com/238e0aefd53420ad50bf
Classpath(3)


• Run
 • jruby pdf_demo.rb
Loading Classes(1)
Document = com.itextpdf.text.Document
Paragraph = com.itextpdf.text.Paragraph
        ...

pdf = Document.new
para = Paragraph.new 'Loading Classes'
        ...
                 https://gist.github.com/82571dca5b9ae6fb9709
Loading Classes(2)
java_import com.itextpdf.text.Document
java_import com.itextpdf.text.Paragraph
        ...

pdf = Document.new
para = Paragraph.new 'Loading Classes'
        ...
                 https://gist.github.com/3f494f48834c8db4f06d
Loading Classes(3)
module IText
  include_package "com.itextpdf.text"
end
        ...
pdf = IText::Document.new
para = IText::Paragraph.new 'Loading...'
        ...
                 https://gist.github.com/da54b499d1ce8e2d38e3
Loading Classes(4)
#for java string
java_import "java.lang.String" do
    "JString"
end
        ...

data = JString.new('avoid class name
conflict')
para = Paragraph.new(data)
             https://gist.github.com/f4acbe684e4c1d9982b1
Using Objects’ Static
        Methods(1)
API: com.itextpdf.text.PageSize




              http://api.itextpdf.com/itext/com/itextpdf/text/PageSize.html
Using Objects’ Static
       Methods(2)
#for itext
java_import com.itextpdf.text.Document
java_import com.itextpdf.text.PageSize
           ...

pdf = Document.new(
PageSize.getRectangle("A5"))

                 https://gist.github.com/a680fe7f47ab00967914
Using Objects’ Static
             Fields
java_import com.itextpdf.text.Document
java_import com.itextpdf.text.PageSize
          ...

pdf    = Document.new(PageSize::A5)


                  https://gist.github.com/a680fe7f47ab00967914
Using Objects’
      constructor(1)
API: com.itextpdf.text.Document




       http://api.itextpdf.com/itext/com/itextpdf/text/Document.html
Using Objects’
          constructor(2)
java_import com.itextpdf.text.Document
java_import com.itextpdf.text.PageSize
          ...

pdf   = Document.new
pdf   = Document.new PageSize::A5
pdf   = Document.new(PageSize::A5, 30,
10,   100, 20)
Get/Set Methods(1)
para = Paragraph.new 'Get/Set methods'

para.setAlignment(10)
para.alignment = 10

puts para.getAlignment #=> 10
puts para.alignment    #=> 10
               https://gist.github.com/50f2d2c82f43db1a886f
Get/Set Methods(2)
pdf = Document.new

pdf.setPageSize(PageSize::A5)
pdf.set_page_size(PageSize::A5)
#pdf.page_size = PageSize::A5 is not work

puts pdf.getPageSize
puts pdf.page_size
                 https://gist.github.com/50f2d2c82f43db1a886f
Using Objects’ Instance
       Fields(1)
// PrivateField.java
public class PrivateField{
    private int pField = 0;
    public PrivateField(int i){
      pField = i;
    }
}
               https://gist.github.com/c078f579c92e0a11fa43
Using Objects’ Instance
       Fields(2)
#private_field.rb
class PrivateField
  field_accessor :pField
end

obj = PrivateField.new(5)
puts obj.pField #=> 5
obj.pField = 10
puts obj.pField #=> 10
               https://gist.github.com/6ae88c3a4472a5b91140
Data Type Conversion




http://kenai.com/projects/jruby/pages/CallingJavaFromJRuby#Ruby_to_Java
Data Type Conversion
           (Array)
public class ArrayDemo {
    public static String getType(Object o){
        return o.getClass().getName();
    }
}



                         https://gist.github.com/1172412
Data Type Conversion
           (Array)
require 'java'
java_import "ArrayDemo"

puts ArrayDemo.get_type(["a", "b"])
#=>org.jruby.RubyArray
puts ArrayDemo. get_type(["a", "b"].to_java)
#=> [Ljava.lang.Object;

                    https://gist.github.com/717f4e5061b8f3f042d5
Multithread(1)

java_import java.lang.Runnable
java_import java.lang.Thread




               https://gist.github.com/1172409
Multithread(2)
class GeneratePdf
  include Runnable

  def initialize
    @runner = Thread.current_thread
  end

  def run
    # Generate PDF
  end
end
Multithread(3)

(1..100).each do
  Thread.new(GeneratePdf.new).start
end
Multithread(4)-peach

  require 'rubygems'
  require 'peach'

  (1..100).to_a.peach do |i|
    # Generate PDF
  end


                https://gist.github.com/1172403
JRoR on Windows
   Environment
Using MSSQL(1)
Step1: add adapter
#Gemfile
gem 'activerecord-jdbc-adapter'
gem 'activerecord-jdbcmssql-adapter'
Using MSSQL(2)
  Step2: Download sqljdbc4.jar


  Step3: add classpath
#config/environment.rb
require "#{Rails.root}/lib/java/sqljdbc4.jar"
Using MSSQL(3)
Step4: config database
development:
 adapter: jdbc
 username: sa
 password: password
 driver: com.microsoft.sqlserver.jdbc.SQLServerDriver
 url: jdbc:sqlserver://hostname:1433;databaseName=myapp
 pool: 5
 timeout: 5000
Application Server
         Trinidad
• Simple library to run rails and rackup
  applications into an embedded Apache
  Tomcat
• https://github.com/trinidad/trinidad
• add gem ‘trinidad’ to Gemfile
• jruby -S trinidad
Running Trinidad as
  Windows Service(1)

• add gem ‘trinidad_init_services’ to Gemfile
• https://github.com/trinidad/
  trinidad_init_services
• It’s base on Apache Commons Daemon
Running Trinidad as
  Windows Service(2)

• If you are using 64-bit Server, you should
  replace procrun.exe to 64-bit version.
• jruby -S trinidad_init_service
IIS Proxy to Trinidad
• using ISAPI_Rewrite 3
• config:
   RewriteEngine on
   RewriteBase /
   RewriteLog "C:myapplogrewrite.log"
   RewriteLogLevel 9
   RewriteProxy (.*) http://localhost:3000/$1



• Single server license: $99
Background Process
          Resque
• redis:
    •   https://github.com/dmajkic/redis/downloads

• resque:
    •   https://github.com/defunkt/resque

•   jruby" -S rake resque:workers VERBOSE=true
    COUNT=3 QUEUE=* RAILS_ENV=production
Deployment
Using NSIS to Deploy Rails App
Steps

• Install JRuby
• Copy app to suitable folder
• Batch file for install gems
• Batch file for database setting
• Batch files for running resque, redis
Install JRuby
Section -InstallJRuby SEC0000
    SetOutPath $INSTDIR
    File /r jruby_windowsjre_1_6_3.exe
    ExecWait '$INSTDIR
jruby_windowsjre_1_6_3.exe -q -dir
"$INSTDIRjruby"'
SectionEnd
Copy App to Suitable
      Folder
Section -CopyMyapp SEC0001
    SetOutPath $INSTDIRmyapp
    SetOverwrite on
    File /r Myapp*
SectionEnd
Batch File for
            Install Gems(1)
Section -CreateFileForGemInstall SEC0003
    FileOpen $9 '$INSTDIRMyappscriptinstall_gem.bat' 'w'
    FileWrite $9 '@echo off$r$n'
    FileWrite $9 'CD /D "$INSTDIRMyapp"$r$n'
    FileWrite $9 'set PATH=$INSTDIRjrubybin$r$n'
    FileWrite $9 '"$INSTDIRjrubybinjruby" -S gem install
"vendorcachebundler-1.0.18.gem"$r$n'
    FileWrite $9 '"$INSTDIRjrubybinjruby" -S bundle
install --local$r$n'
    FileClose $9
SectionEnd
Batch File for
         Database Setting
Section -CreateFileForDBConfig SEC0005
    FileOpen $9 '$INSTDIRMyappscriptconfig_db.bat' 'w'
    FileWrite $9 '@echo off$r$n'
    FileWrite $9 'CD /D "$INSTDIRMyapp"$r$n'
    FileWrite $9 '"$INSTDIRjrubybinjruby" -S rake
db:migrate RAILS_ENV=production$r$n'
    FileWrite $9 '"$INSTDIRjrubybinjruby" -S rake
db:seed RAILS_ENV=production$r$n'
    FileClose $9
SectionEnd
Batch File for Redis

Section -CreateFileForRedis SEC0007
    FileOpen $9 '$INSTDIRMyappscriptredis.bat' 'w'
    FileWrite $9 '@echo off$r$n'
    FileWrite $9 '"$INSTDIRredisredis-server.exe"$r$n'
    FileClose $9
SectionEnd
Batch File for Resque
Section -CreateFileForResque SEC0008
    FileOpen $9 '$INSTDIRMyappscriptresque.bat' 'w'
    FileWrite $9 '@echo off$r$n'
    FileWrite $9 'CD /D "$INSTDIRMyapp"$r$n'
    FileWrite $9 '"$INSTDIRjrubybinjruby" -S rake resque:workers
VERBOSE=true COUNT=3 QUEUE=* RAILS_ENV=production$r$n'
    FileClose $9
SectionEnd
Redis and Resque are running
on the “Command Prompt”.

hmm.....

It’s not a good idea.
Using FireDaemon

• Windows Service Creation, Management,
  Monitoring and Control
• http://www.firedaemon.com/purchase-
  firedaemon.php
• Single License:
$49
Q&A

Contenu connexe

Tendances

An Introduction to Celery
An Introduction to CeleryAn Introduction to Celery
An Introduction to CeleryIdan Gazit
 
Python virtualenv & pip in 90 minutes
Python virtualenv & pip in 90 minutesPython virtualenv & pip in 90 minutes
Python virtualenv & pip in 90 minutesLarry Cai
 
Fabric workshop(1) - (MOSG)
Fabric workshop(1) - (MOSG)Fabric workshop(1) - (MOSG)
Fabric workshop(1) - (MOSG)Soshi Nemoto
 
Building Distributed System with Celery on Docker Swarm
Building Distributed System with Celery on Docker SwarmBuilding Distributed System with Celery on Docker Swarm
Building Distributed System with Celery on Docker SwarmWei Lin
 
Making environment for_infrastructure_as_code
Making environment for_infrastructure_as_codeMaking environment for_infrastructure_as_code
Making environment for_infrastructure_as_codeSoshi Nemoto
 
[2C1] 아파치 피그를 위한 테즈 연산 엔진 개발하기 최종
[2C1] 아파치 피그를 위한 테즈 연산 엔진 개발하기 최종[2C1] 아파치 피그를 위한 테즈 연산 엔진 개발하기 최종
[2C1] 아파치 피그를 위한 테즈 연산 엔진 개발하기 최종NAVER D2
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissAndres Almiray
 
Programming language for the cloud infrastructure
Programming language for the cloud infrastructureProgramming language for the cloud infrastructure
Programming language for the cloud infrastructureYaroslav Muravskyi
 
Rapid web development using tornado web and mongodb
Rapid web development using tornado web and mongodbRapid web development using tornado web and mongodb
Rapid web development using tornado web and mongodbikailan
 
Tornado Web Server Internals
Tornado Web Server InternalsTornado Web Server Internals
Tornado Web Server InternalsPraveen Gollakota
 
Big query - Command line tools and Tips - (MOSG)
Big query - Command line tools and Tips - (MOSG)Big query - Command line tools and Tips - (MOSG)
Big query - Command line tools and Tips - (MOSG)Soshi Nemoto
 
Ship your Scala code often and easy with Docker
Ship your Scala code often and easy with DockerShip your Scala code often and easy with Docker
Ship your Scala code often and easy with DockerMarcus Lönnberg
 
Python, async web frameworks, and MongoDB
Python, async web frameworks, and MongoDBPython, async web frameworks, and MongoDB
Python, async web frameworks, and MongoDBemptysquare
 
Exploring the Titanium CLI - Codestrong 2012
Exploring the Titanium CLI - Codestrong 2012Exploring the Titanium CLI - Codestrong 2012
Exploring the Titanium CLI - Codestrong 2012Chris Barber
 
A Hands-on Introduction on Terraform Best Concepts and Best Practices
A Hands-on Introduction on Terraform Best Concepts and Best Practices A Hands-on Introduction on Terraform Best Concepts and Best Practices
A Hands-on Introduction on Terraform Best Concepts and Best Practices Nebulaworks
 
Docker @ Data Science Meetup
Docker @ Data Science MeetupDocker @ Data Science Meetup
Docker @ Data Science MeetupDaniel Nüst
 
Titanium 3.2 CLI - TiAppCamp2 - 11/2/2013
Titanium 3.2 CLI - TiAppCamp2 - 11/2/2013Titanium 3.2 CLI - TiAppCamp2 - 11/2/2013
Titanium 3.2 CLI - TiAppCamp2 - 11/2/2013Chris Barber
 
[LDSP] Search Engine Back End API Solution for Fast Prototyping
[LDSP] Search Engine Back End API Solution for Fast Prototyping[LDSP] Search Engine Back End API Solution for Fast Prototyping
[LDSP] Search Engine Back End API Solution for Fast PrototypingJimmy Lai
 
Effective iOS Network Programming Techniques
Effective iOS Network Programming TechniquesEffective iOS Network Programming Techniques
Effective iOS Network Programming TechniquesBen Scheirman
 

Tendances (20)

An Introduction to Celery
An Introduction to CeleryAn Introduction to Celery
An Introduction to Celery
 
Python virtualenv & pip in 90 minutes
Python virtualenv & pip in 90 minutesPython virtualenv & pip in 90 minutes
Python virtualenv & pip in 90 minutes
 
Fabric workshop(1) - (MOSG)
Fabric workshop(1) - (MOSG)Fabric workshop(1) - (MOSG)
Fabric workshop(1) - (MOSG)
 
Building Distributed System with Celery on Docker Swarm
Building Distributed System with Celery on Docker SwarmBuilding Distributed System with Celery on Docker Swarm
Building Distributed System with Celery on Docker Swarm
 
Making environment for_infrastructure_as_code
Making environment for_infrastructure_as_codeMaking environment for_infrastructure_as_code
Making environment for_infrastructure_as_code
 
Gradle Introduction
Gradle IntroductionGradle Introduction
Gradle Introduction
 
[2C1] 아파치 피그를 위한 테즈 연산 엔진 개발하기 최종
[2C1] 아파치 피그를 위한 테즈 연산 엔진 개발하기 최종[2C1] 아파치 피그를 위한 테즈 연산 엔진 개발하기 최종
[2C1] 아파치 피그를 위한 테즈 연산 엔진 개발하기 최종
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 
Programming language for the cloud infrastructure
Programming language for the cloud infrastructureProgramming language for the cloud infrastructure
Programming language for the cloud infrastructure
 
Rapid web development using tornado web and mongodb
Rapid web development using tornado web and mongodbRapid web development using tornado web and mongodb
Rapid web development using tornado web and mongodb
 
Tornado Web Server Internals
Tornado Web Server InternalsTornado Web Server Internals
Tornado Web Server Internals
 
Big query - Command line tools and Tips - (MOSG)
Big query - Command line tools and Tips - (MOSG)Big query - Command line tools and Tips - (MOSG)
Big query - Command line tools and Tips - (MOSG)
 
Ship your Scala code often and easy with Docker
Ship your Scala code often and easy with DockerShip your Scala code often and easy with Docker
Ship your Scala code often and easy with Docker
 
Python, async web frameworks, and MongoDB
Python, async web frameworks, and MongoDBPython, async web frameworks, and MongoDB
Python, async web frameworks, and MongoDB
 
Exploring the Titanium CLI - Codestrong 2012
Exploring the Titanium CLI - Codestrong 2012Exploring the Titanium CLI - Codestrong 2012
Exploring the Titanium CLI - Codestrong 2012
 
A Hands-on Introduction on Terraform Best Concepts and Best Practices
A Hands-on Introduction on Terraform Best Concepts and Best Practices A Hands-on Introduction on Terraform Best Concepts and Best Practices
A Hands-on Introduction on Terraform Best Concepts and Best Practices
 
Docker @ Data Science Meetup
Docker @ Data Science MeetupDocker @ Data Science Meetup
Docker @ Data Science Meetup
 
Titanium 3.2 CLI - TiAppCamp2 - 11/2/2013
Titanium 3.2 CLI - TiAppCamp2 - 11/2/2013Titanium 3.2 CLI - TiAppCamp2 - 11/2/2013
Titanium 3.2 CLI - TiAppCamp2 - 11/2/2013
 
[LDSP] Search Engine Back End API Solution for Fast Prototyping
[LDSP] Search Engine Back End API Solution for Fast Prototyping[LDSP] Search Engine Back End API Solution for Fast Prototyping
[LDSP] Search Engine Back End API Solution for Fast Prototyping
 
Effective iOS Network Programming Techniques
Effective iOS Network Programming TechniquesEffective iOS Network Programming Techniques
Effective iOS Network Programming Techniques
 

En vedette

PME DJ Service Presentation
PME DJ Service PresentationPME DJ Service Presentation
PME DJ Service PresentationMark Sanchez
 
Mock Aren't Stub 讀後心得
Mock Aren't Stub 讀後心得Mock Aren't Stub 讀後心得
Mock Aren't Stub 讀後心得Wei Jen Lu
 
BDD for Rails Legacy Code
BDD for Rails Legacy CodeBDD for Rails Legacy Code
BDD for Rails Legacy CodeWei Jen Lu
 
Trend Report
Trend ReportTrend Report
Trend Reportmward0118
 
SESC / Biennial by Ilaria Montorsi and Giovanni Saladino
SESC / Biennial by Ilaria Montorsi and Giovanni  SaladinoSESC / Biennial by Ilaria Montorsi and Giovanni  Saladino
SESC / Biennial by Ilaria Montorsi and Giovanni Saladinovsideris
 
Fiberstars Design Presentation 2009
Fiberstars Design Presentation 2009Fiberstars Design Presentation 2009
Fiberstars Design Presentation 2009Jason Cordon
 

En vedette (8)

PME DJ Service Presentation
PME DJ Service PresentationPME DJ Service Presentation
PME DJ Service Presentation
 
Mock Aren't Stub 讀後心得
Mock Aren't Stub 讀後心得Mock Aren't Stub 讀後心得
Mock Aren't Stub 讀後心得
 
BDD for Ruby
BDD for RubyBDD for Ruby
BDD for Ruby
 
BDD for Rails Legacy Code
BDD for Rails Legacy CodeBDD for Rails Legacy Code
BDD for Rails Legacy Code
 
Trend Report
Trend ReportTrend Report
Trend Report
 
Presentation1
Presentation1Presentation1
Presentation1
 
SESC / Biennial by Ilaria Montorsi and Giovanni Saladino
SESC / Biennial by Ilaria Montorsi and Giovanni  SaladinoSESC / Biennial by Ilaria Montorsi and Giovanni  Saladino
SESC / Biennial by Ilaria Montorsi and Giovanni Saladino
 
Fiberstars Design Presentation 2009
Fiberstars Design Presentation 2009Fiberstars Design Presentation 2009
Fiberstars Design Presentation 2009
 

Similaire à 把鐵路開進視窗裡

Bangpypers april-meetup-2012
Bangpypers april-meetup-2012Bangpypers april-meetup-2012
Bangpypers april-meetup-2012Deepak Garg
 
Testing of javacript
Testing of javacriptTesting of javacript
Testing of javacriptLei Kang
 
Docker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline ExecutionDocker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline ExecutionBrennan Saeta
 
Tdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema RubyTdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema RubyFabio Akita
 
Meetup Performance
Meetup PerformanceMeetup Performance
Meetup PerformanceGreg Whalin
 
Play Support in Cloud Foundry
Play Support in Cloud FoundryPlay Support in Cloud Foundry
Play Support in Cloud Foundryrajdeep
 
Django deployment with PaaS
Django deployment with PaaSDjango deployment with PaaS
Django deployment with PaaSAppsembler
 
RichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile DevicesRichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile DevicesPavol Pitoňák
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Enginecatherinewall
 
Persistent mobile JavaScript
Persistent mobile JavaScriptPersistent mobile JavaScript
Persistent mobile JavaScriptYorick Phoenix
 
Taking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the ExtremeTaking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the Extremeyinonavraham
 
Fullstack workshop
Fullstack workshopFullstack workshop
Fullstack workshopAssaf Gannon
 
Harmonious Development: Via Vagrant and Puppet
Harmonious Development: Via Vagrant and PuppetHarmonious Development: Via Vagrant and Puppet
Harmonious Development: Via Vagrant and PuppetAchieve Internet
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
Complex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBoxComplex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBoxbobmcwhirter
 
Server Side JavaScript - You ain't seen nothing yet
Server Side JavaScript - You ain't seen nothing yetServer Side JavaScript - You ain't seen nothing yet
Server Side JavaScript - You ain't seen nothing yetTom Croucher
 
Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!Roberto Franchini
 
Plugin-based software design with Ruby and RubyGems
Plugin-based software design with Ruby and RubyGemsPlugin-based software design with Ruby and RubyGems
Plugin-based software design with Ruby and RubyGemsSadayuki Furuhashi
 

Similaire à 把鐵路開進視窗裡 (20)

Bangpypers april-meetup-2012
Bangpypers april-meetup-2012Bangpypers april-meetup-2012
Bangpypers april-meetup-2012
 
Testing of javacript
Testing of javacriptTesting of javacript
Testing of javacript
 
Docker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline ExecutionDocker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline Execution
 
Tdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema RubyTdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema Ruby
 
Meetup Performance
Meetup PerformanceMeetup Performance
Meetup Performance
 
Meetup Performance
Meetup PerformanceMeetup Performance
Meetup Performance
 
Play Support in Cloud Foundry
Play Support in Cloud FoundryPlay Support in Cloud Foundry
Play Support in Cloud Foundry
 
Js tacktalk team dev js testing performance
Js tacktalk team dev js testing performanceJs tacktalk team dev js testing performance
Js tacktalk team dev js testing performance
 
Django deployment with PaaS
Django deployment with PaaSDjango deployment with PaaS
Django deployment with PaaS
 
RichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile DevicesRichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile Devices
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Engine
 
Persistent mobile JavaScript
Persistent mobile JavaScriptPersistent mobile JavaScript
Persistent mobile JavaScript
 
Taking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the ExtremeTaking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the Extreme
 
Fullstack workshop
Fullstack workshopFullstack workshop
Fullstack workshop
 
Harmonious Development: Via Vagrant and Puppet
Harmonious Development: Via Vagrant and PuppetHarmonious Development: Via Vagrant and Puppet
Harmonious Development: Via Vagrant and Puppet
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
Complex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBoxComplex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBox
 
Server Side JavaScript - You ain't seen nothing yet
Server Side JavaScript - You ain't seen nothing yetServer Side JavaScript - You ain't seen nothing yet
Server Side JavaScript - You ain't seen nothing yet
 
Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!
 
Plugin-based software design with Ruby and RubyGems
Plugin-based software design with Ruby and RubyGemsPlugin-based software design with Ruby and RubyGems
Plugin-based software design with Ruby and RubyGems
 

Dernier

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 

Dernier (20)

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 

把鐵路開進視窗裡

  • 1. Deploy JRuby on Rails to Windows Server 2008 R2
  • 2. About Me • (Lu Wei Jen) • • http://www.handlino.com • Facebook: http://www.facebook.com/weijenlu • Twitter: weijenlu
  • 3. Agenda • Why Windows • Why JRuby • Using Java’s Resources • JRoR on Windows Environment • Deployment
  • 6. Q1 2010 units Q1 2010 dollars Windows 1,379,487 (75.3%) Windows $5.1 billion (48.9%) Unix 65,451 (3.6%) Unix $2.3 billion (22.2%) Linux 380,429 (20.8%) Linux $1.7 billion (16.2%) Q4 2009 units Q4 2009 dollars Windows 1,434,225 (73.9%) Windows $5.4 billion (41.6%) Unix 84,851 ( 4.4%) Unix $3.9 billion (29.9%) Linux 412,041 (21.2%) Linux $1.9 billion (14.7%) http://www.zdnet.com/blog/microsoft/idc-windows-server-still-rules-the-server-roost/6424
  • 9. More Jobs More Rubiest More Resources
  • 10. More Jobs More Rubiest More Resources More Money
  • 11. Why JRuby • You can use java resources. • More easy to deploy to Windows. • True multithreading. • JRuby is just a .jar file. http://bit.ly/cPNg9f
  • 13. Wrapping a Library(1) require 'java' # create objects pdf = com.itextpdf.text.Document.new para = com.itextpdf.text.Paragraph.new 'Using Java resources from JRuby' file = java.io.FileOutputStream.new 'pdf_demo.pdf' https://gist.github.com/e4b1d813394e58188e59
  • 14. Wrapping a Library(2) # get_instance is an alias for getInstance com.itextpdf.text.pdf.PdfWriter. get_instance(pdf, file) pdf.open pdf.add para pdf.close https://gist.github.com/e4b1d813394e58188e59
  • 15. Wrapping a Library(3) • Run • jruby -J-cp itextpdf-5.1.2.jar pdf_demo.rb
  • 16. Classpath(1) • Environment Variable • set RUBYOPT=-IC:jrubyitext • set CLASSPATH=%CLASSPATH%C:jruby itext
  • 18. Classpath(3) • Run • jruby pdf_demo.rb
  • 19. Loading Classes(1) Document = com.itextpdf.text.Document Paragraph = com.itextpdf.text.Paragraph ... pdf = Document.new para = Paragraph.new 'Loading Classes' ... https://gist.github.com/82571dca5b9ae6fb9709
  • 20. Loading Classes(2) java_import com.itextpdf.text.Document java_import com.itextpdf.text.Paragraph ... pdf = Document.new para = Paragraph.new 'Loading Classes' ... https://gist.github.com/3f494f48834c8db4f06d
  • 21. Loading Classes(3) module IText include_package "com.itextpdf.text" end ... pdf = IText::Document.new para = IText::Paragraph.new 'Loading...' ... https://gist.github.com/da54b499d1ce8e2d38e3
  • 22. Loading Classes(4) #for java string java_import "java.lang.String" do "JString" end ... data = JString.new('avoid class name conflict') para = Paragraph.new(data) https://gist.github.com/f4acbe684e4c1d9982b1
  • 23. Using Objects’ Static Methods(1) API: com.itextpdf.text.PageSize http://api.itextpdf.com/itext/com/itextpdf/text/PageSize.html
  • 24. Using Objects’ Static Methods(2) #for itext java_import com.itextpdf.text.Document java_import com.itextpdf.text.PageSize ... pdf = Document.new( PageSize.getRectangle("A5")) https://gist.github.com/a680fe7f47ab00967914
  • 25. Using Objects’ Static Fields java_import com.itextpdf.text.Document java_import com.itextpdf.text.PageSize ... pdf = Document.new(PageSize::A5) https://gist.github.com/a680fe7f47ab00967914
  • 26. Using Objects’ constructor(1) API: com.itextpdf.text.Document http://api.itextpdf.com/itext/com/itextpdf/text/Document.html
  • 27. Using Objects’ constructor(2) java_import com.itextpdf.text.Document java_import com.itextpdf.text.PageSize ... pdf = Document.new pdf = Document.new PageSize::A5 pdf = Document.new(PageSize::A5, 30, 10, 100, 20)
  • 28. Get/Set Methods(1) para = Paragraph.new 'Get/Set methods' para.setAlignment(10) para.alignment = 10 puts para.getAlignment #=> 10 puts para.alignment #=> 10 https://gist.github.com/50f2d2c82f43db1a886f
  • 29. Get/Set Methods(2) pdf = Document.new pdf.setPageSize(PageSize::A5) pdf.set_page_size(PageSize::A5) #pdf.page_size = PageSize::A5 is not work puts pdf.getPageSize puts pdf.page_size https://gist.github.com/50f2d2c82f43db1a886f
  • 30. Using Objects’ Instance Fields(1) // PrivateField.java public class PrivateField{ private int pField = 0; public PrivateField(int i){ pField = i; } } https://gist.github.com/c078f579c92e0a11fa43
  • 31. Using Objects’ Instance Fields(2) #private_field.rb class PrivateField field_accessor :pField end obj = PrivateField.new(5) puts obj.pField #=> 5 obj.pField = 10 puts obj.pField #=> 10 https://gist.github.com/6ae88c3a4472a5b91140
  • 32.
  • 34. Data Type Conversion (Array) public class ArrayDemo { public static String getType(Object o){ return o.getClass().getName(); } } https://gist.github.com/1172412
  • 35. Data Type Conversion (Array) require 'java' java_import "ArrayDemo" puts ArrayDemo.get_type(["a", "b"]) #=>org.jruby.RubyArray puts ArrayDemo. get_type(["a", "b"].to_java) #=> [Ljava.lang.Object; https://gist.github.com/717f4e5061b8f3f042d5
  • 37. Multithread(2) class GeneratePdf include Runnable def initialize @runner = Thread.current_thread end def run # Generate PDF end end
  • 38. Multithread(3) (1..100).each do Thread.new(GeneratePdf.new).start end
  • 39. Multithread(4)-peach require 'rubygems' require 'peach' (1..100).to_a.peach do |i| # Generate PDF end https://gist.github.com/1172403
  • 40. JRoR on Windows Environment
  • 41. Using MSSQL(1) Step1: add adapter #Gemfile gem 'activerecord-jdbc-adapter' gem 'activerecord-jdbcmssql-adapter'
  • 42. Using MSSQL(2) Step2: Download sqljdbc4.jar Step3: add classpath #config/environment.rb require "#{Rails.root}/lib/java/sqljdbc4.jar"
  • 43. Using MSSQL(3) Step4: config database development: adapter: jdbc username: sa password: password driver: com.microsoft.sqlserver.jdbc.SQLServerDriver url: jdbc:sqlserver://hostname:1433;databaseName=myapp pool: 5 timeout: 5000
  • 44. Application Server Trinidad • Simple library to run rails and rackup applications into an embedded Apache Tomcat • https://github.com/trinidad/trinidad • add gem ‘trinidad’ to Gemfile • jruby -S trinidad
  • 45. Running Trinidad as Windows Service(1) • add gem ‘trinidad_init_services’ to Gemfile • https://github.com/trinidad/ trinidad_init_services • It’s base on Apache Commons Daemon
  • 46. Running Trinidad as Windows Service(2) • If you are using 64-bit Server, you should replace procrun.exe to 64-bit version. • jruby -S trinidad_init_service
  • 47. IIS Proxy to Trinidad • using ISAPI_Rewrite 3 • config: RewriteEngine on RewriteBase / RewriteLog "C:myapplogrewrite.log" RewriteLogLevel 9 RewriteProxy (.*) http://localhost:3000/$1 • Single server license: $99
  • 48. Background Process Resque • redis: • https://github.com/dmajkic/redis/downloads • resque: • https://github.com/defunkt/resque • jruby" -S rake resque:workers VERBOSE=true COUNT=3 QUEUE=* RAILS_ENV=production
  • 49. Deployment Using NSIS to Deploy Rails App
  • 50. Steps • Install JRuby • Copy app to suitable folder • Batch file for install gems • Batch file for database setting • Batch files for running resque, redis
  • 51. Install JRuby Section -InstallJRuby SEC0000 SetOutPath $INSTDIR File /r jruby_windowsjre_1_6_3.exe ExecWait '$INSTDIR jruby_windowsjre_1_6_3.exe -q -dir "$INSTDIRjruby"' SectionEnd
  • 52. Copy App to Suitable Folder Section -CopyMyapp SEC0001 SetOutPath $INSTDIRmyapp SetOverwrite on File /r Myapp* SectionEnd
  • 53. Batch File for Install Gems(1) Section -CreateFileForGemInstall SEC0003 FileOpen $9 '$INSTDIRMyappscriptinstall_gem.bat' 'w' FileWrite $9 '@echo off$r$n' FileWrite $9 'CD /D "$INSTDIRMyapp"$r$n' FileWrite $9 'set PATH=$INSTDIRjrubybin$r$n' FileWrite $9 '"$INSTDIRjrubybinjruby" -S gem install "vendorcachebundler-1.0.18.gem"$r$n' FileWrite $9 '"$INSTDIRjrubybinjruby" -S bundle install --local$r$n' FileClose $9 SectionEnd
  • 54. Batch File for Database Setting Section -CreateFileForDBConfig SEC0005 FileOpen $9 '$INSTDIRMyappscriptconfig_db.bat' 'w' FileWrite $9 '@echo off$r$n' FileWrite $9 'CD /D "$INSTDIRMyapp"$r$n' FileWrite $9 '"$INSTDIRjrubybinjruby" -S rake db:migrate RAILS_ENV=production$r$n' FileWrite $9 '"$INSTDIRjrubybinjruby" -S rake db:seed RAILS_ENV=production$r$n' FileClose $9 SectionEnd
  • 55. Batch File for Redis Section -CreateFileForRedis SEC0007 FileOpen $9 '$INSTDIRMyappscriptredis.bat' 'w' FileWrite $9 '@echo off$r$n' FileWrite $9 '"$INSTDIRredisredis-server.exe"$r$n' FileClose $9 SectionEnd
  • 56. Batch File for Resque Section -CreateFileForResque SEC0008 FileOpen $9 '$INSTDIRMyappscriptresque.bat' 'w' FileWrite $9 '@echo off$r$n' FileWrite $9 'CD /D "$INSTDIRMyapp"$r$n' FileWrite $9 '"$INSTDIRjrubybinjruby" -S rake resque:workers VERBOSE=true COUNT=3 QUEUE=* RAILS_ENV=production$r$n' FileClose $9 SectionEnd
  • 57. Redis and Resque are running on the “Command Prompt”. hmm..... It’s not a good idea.
  • 58. Using FireDaemon • Windows Service Creation, Management, Monitoring and Control • http://www.firedaemon.com/purchase- firedaemon.php • Single License: $49
  • 59. Q&A

Notes de l'éditeur

  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
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n