SlideShare une entreprise Scribd logo
1  sur  9
Télécharger pour lire hors ligne
it’s only abuse if it crashes
the art of low-level ruby and other macabre tales


Eleanor McHugh
http://slides.games-with-brains.net/
with Kernel.syscall
process 1                                            process 2

  require ‘fcntl’                                      Open, Wait, TryWait, Post = 268, 271, 272, 273
  Open, Wait, Post, Close = 268, 271, 273, 269         s = syscall Open, “/tmp/s”
  s = syscall Open, “/tmp/s”, Fcntl::O_CREAT, 1911     begin
  syscall Wait, s                                           t = Time.now
  puts “locked at #{Time.now}”                              syscall TryWait, s
  sleep 50                                                  puts “locked at #{t}”
  puts “posted at #{Time.now}”                         rescue Exception => e
  syscall Post, s                                           puts “busy at #{t}”
  syscall Close, s                                          syscall Wait, s
                                                            puts “waited #{Time.now - t} seconds”
                                                       end


produces:                                            produces:
  locked at Thu May 28 01:03:23 +0100 2009             busy at Thu May 28 01:03:36 +0100 2009
  posted at Thu May 28 01:04:13 +0100 2009             waited 47.056508 seconds
or the ruby/dl way
  require ‘dl’
  require ‘fcntl’
  LIBC = DL::dlopen ‘libc.dylib’
  open = LIBC[‘sem_open’, ‘ISII’]
  try_wait = LIBC[‘sem_trywait’, ‘II’]
  wait = LIBC[‘sem_wait’, ‘II’]
  post = LIBC[‘sem_post’, ‘II’]
  close = LIBC[‘sem_close’, ‘II’]


process 1                                            process 2
  s = open.call(“/tmp/s”, Fcntl::O_CREAT, 1911)[0]     s = open.call(“/tmp/s”)
  wait.call s                                          t = Time.now
  puts “locked at #{Time.now}”                         if try_wait.call(s)[0] == 0 then
  sleep 50                                                   puts “locked at #{t}”
  puts “posted at #{Time.now}”                         else
  post.call s                                                puts “busy at #{t}”
  close.call s                                               wait.call s
                                                             puts “waited #{Time.now - t} seconds”
  => locked at Thu May 28 01:03:23 +0100 2009          end
  => posted at Thu May 28 01:04:13 +0100 2009
                                                       => busy at Thu May 28 01:03:36 +0100 2009
                                                       => waited 47.056508 seconds
ruby + malloc = fun
require ‘dl’

memory_buffer = DL::malloc 20
=> #<DL::PtrData:0x2d0870 ptr=0x820600 size=20 free=0x1b0257>

memory_buffer[0] = “hello world!”
=> “hello world!000000000000000000000000"

memory_buffer.free
=> #<DL::Symbol:0x40b760 func=0x1b0257 'void (free)(void *);'>

memory_buffer.nil
=> nil
and frustration
string = “hello ruby”
memory_buffer = string.to_ptr
=> #<DL::PtrData:0x41bea0 ptr=0x41be60 size=10 free=0x1b0257>

memory_buffer[0] = “goodbye world”
memory_buffer += 1
=> #<DL::PtrData:0x422000 ptr=0x41be61 size=9 free=0x0>

puts memory_buffer, memory_buffer.to_str, string
=> “oodbye world”
=> “oodbye wo”
=> “hello ruby”

memory_buffer -= 1
=> (irb):51: [BUG] Segmentation fault
but we can fix that?
Signal.trap(:SEGV) { $stderr.puts "segfault triggered" }
Process.kill :SEGV, 0
$stderr.puts "but I carry on as usual"

require 'dl'
memory = DL::malloc 1
4096.times { |i| memory[0] = 42.chr * i }
$stderr.puts "even genuine segfaults don't phase me"

produces:
  segfault triggered
  but I carry on as usual
maybe with some tenderlove
require 'dl'
require ‘neversaydie’
memory = DL::malloc 1
4096.times do |i|
 begin
   puts "#{i} : #{(memory[1] = 42.chr * i).length}"
 rescue NeverSayDie => e
   $stderr.puts "even genuine segfaults don't phase me"
   break
 end
end

produces:
  even genuine segfaults don't phase me
but what I really want
require 'dl'
SIGSEGV = DL::dlopen('libsigsegv.dylib')
install_handler = SIGSEGV['sigsegv_install_handler', 'IP']
deinstall_handler = SIGSEGV['sigsegv_deinstall_handler', '0']
leave_handler = SIGSEGV['sigsegv_leave_handler', 'IPPPP']

continuation = DL.callback('IPPP') do |address, b, c|
 raise RuntimeError, "segfault at #{address}"
end

handler = DL.callback('IPI') do |fault_address, serious|
 leave_handler.call continuation, fault_address, nil, nil
end

install_handler.call handler
further reading
 http://www.jbrowse.com/text/rdl_en.html

 http://www.ruby-lang.org/en/downloads/

 http://slides.games-with-brains.net/

Contenu connexe

Tendances

Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++
Yandex
 
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан КольцовRust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Yandex
 
RedHat/CentOs Commands for administrative works
RedHat/CentOs Commands for administrative worksRedHat/CentOs Commands for administrative works
RedHat/CentOs Commands for administrative works
Md Shihab
 
NoSQL com Cassandra e Python
NoSQL com Cassandra e PythonNoSQL com Cassandra e Python
NoSQL com Cassandra e Python
pugpe
 

Tendances (20)

Scaling antispam solutions with Puppet
Scaling antispam solutions with PuppetScaling antispam solutions with Puppet
Scaling antispam solutions with Puppet
 
Cloud Erlang
Cloud ErlangCloud Erlang
Cloud Erlang
 
Border Patrol - Count, throttle, kick & ban in perl
Border Patrol - Count, throttle, kick & ban in perlBorder Patrol - Count, throttle, kick & ban in perl
Border Patrol - Count, throttle, kick & ban in perl
 
Playing 44CON CTF for fun and profit
Playing 44CON CTF for fun and profitPlaying 44CON CTF for fun and profit
Playing 44CON CTF for fun and profit
 
Puppet User Group Presentation - 15 March 2012
Puppet User Group Presentation - 15 March 2012Puppet User Group Presentation - 15 March 2012
Puppet User Group Presentation - 15 March 2012
 
Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++
 
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан КольцовRust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
 
Ethereum virtual machine for Developers Part 1
Ethereum virtual machine for Developers Part 1Ethereum virtual machine for Developers Part 1
Ethereum virtual machine for Developers Part 1
 
RedHat/CentOs Commands for administrative works
RedHat/CentOs Commands for administrative worksRedHat/CentOs Commands for administrative works
RedHat/CentOs Commands for administrative works
 
NoSQL com Cassandra e Python
NoSQL com Cassandra e PythonNoSQL com Cassandra e Python
NoSQL com Cassandra e Python
 
Beyond Golden Containers: Complementing Docker with Puppet
Beyond Golden Containers: Complementing Docker with PuppetBeyond Golden Containers: Complementing Docker with Puppet
Beyond Golden Containers: Complementing Docker with Puppet
 
How to ride a whale
How to ride a whaleHow to ride a whale
How to ride a whale
 
Meetup Javascript for beginner
Meetup Javascript for beginner Meetup Javascript for beginner
Meetup Javascript for beginner
 
IPython from 30,000 feet
IPython from 30,000 feetIPython from 30,000 feet
IPython from 30,000 feet
 
Building real-time apps with WebSockets
Building real-time apps with WebSocketsBuilding real-time apps with WebSockets
Building real-time apps with WebSockets
 
Tackling Asynchrony with Kotlin Coroutines
Tackling Asynchrony with Kotlin CoroutinesTackling Asynchrony with Kotlin Coroutines
Tackling Asynchrony with Kotlin Coroutines
 
OlinData Puppet Presentation for MOSC 2012
OlinData Puppet Presentation for MOSC 2012OlinData Puppet Presentation for MOSC 2012
OlinData Puppet Presentation for MOSC 2012
 
Grand Central Dispatch in Objective-C
Grand Central Dispatch in Objective-CGrand Central Dispatch in Objective-C
Grand Central Dispatch in Objective-C
 
Introduction to rust
Introduction to rustIntroduction to rust
Introduction to rust
 
Presenting Seq for Node.js
Presenting Seq for Node.jsPresenting Seq for Node.js
Presenting Seq for Node.js
 

Plus de Eleanor McHugh

Plus de Eleanor McHugh (20)

[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
 
Generics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsGenerics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient Collections
 
The Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityThe Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data Integrity
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's Perspective
 
Go for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd edition
 
An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]
 
An introduction to functional programming with go
An introduction to functional programming with goAn introduction to functional programming with go
An introduction to functional programming with go
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored Spaces
 
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignDon't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By Design
 
Don't ask, don't tell the virtues of privacy by design
Don't ask, don't tell   the virtues of privacy by designDon't ask, don't tell   the virtues of privacy by design
Don't ask, don't tell the virtues of privacy by design
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trust
 
Going Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoGoing Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google Go
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at Scale
 
Hello Go
Hello GoHello Go
Hello Go
 
Go for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionGo for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd edition
 
Going Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoGoing Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with Go
 
Finding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goFinding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in go
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountability
 

Dernier

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Dernier (20)

FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 

it's only abuse if it crashes

  • 1. it’s only abuse if it crashes the art of low-level ruby and other macabre tales Eleanor McHugh http://slides.games-with-brains.net/
  • 2. with Kernel.syscall process 1 process 2 require ‘fcntl’ Open, Wait, TryWait, Post = 268, 271, 272, 273 Open, Wait, Post, Close = 268, 271, 273, 269 s = syscall Open, “/tmp/s” s = syscall Open, “/tmp/s”, Fcntl::O_CREAT, 1911 begin syscall Wait, s t = Time.now puts “locked at #{Time.now}” syscall TryWait, s sleep 50 puts “locked at #{t}” puts “posted at #{Time.now}” rescue Exception => e syscall Post, s puts “busy at #{t}” syscall Close, s syscall Wait, s puts “waited #{Time.now - t} seconds” end produces: produces: locked at Thu May 28 01:03:23 +0100 2009 busy at Thu May 28 01:03:36 +0100 2009 posted at Thu May 28 01:04:13 +0100 2009 waited 47.056508 seconds
  • 3. or the ruby/dl way require ‘dl’ require ‘fcntl’ LIBC = DL::dlopen ‘libc.dylib’ open = LIBC[‘sem_open’, ‘ISII’] try_wait = LIBC[‘sem_trywait’, ‘II’] wait = LIBC[‘sem_wait’, ‘II’] post = LIBC[‘sem_post’, ‘II’] close = LIBC[‘sem_close’, ‘II’] process 1 process 2 s = open.call(“/tmp/s”, Fcntl::O_CREAT, 1911)[0] s = open.call(“/tmp/s”) wait.call s t = Time.now puts “locked at #{Time.now}” if try_wait.call(s)[0] == 0 then sleep 50 puts “locked at #{t}” puts “posted at #{Time.now}” else post.call s puts “busy at #{t}” close.call s wait.call s puts “waited #{Time.now - t} seconds” => locked at Thu May 28 01:03:23 +0100 2009 end => posted at Thu May 28 01:04:13 +0100 2009 => busy at Thu May 28 01:03:36 +0100 2009 => waited 47.056508 seconds
  • 4. ruby + malloc = fun require ‘dl’ memory_buffer = DL::malloc 20 => #<DL::PtrData:0x2d0870 ptr=0x820600 size=20 free=0x1b0257> memory_buffer[0] = “hello world!” => “hello world!000000000000000000000000" memory_buffer.free => #<DL::Symbol:0x40b760 func=0x1b0257 'void (free)(void *);'> memory_buffer.nil => nil
  • 5. and frustration string = “hello ruby” memory_buffer = string.to_ptr => #<DL::PtrData:0x41bea0 ptr=0x41be60 size=10 free=0x1b0257> memory_buffer[0] = “goodbye world” memory_buffer += 1 => #<DL::PtrData:0x422000 ptr=0x41be61 size=9 free=0x0> puts memory_buffer, memory_buffer.to_str, string => “oodbye world” => “oodbye wo” => “hello ruby” memory_buffer -= 1 => (irb):51: [BUG] Segmentation fault
  • 6. but we can fix that? Signal.trap(:SEGV) { $stderr.puts "segfault triggered" } Process.kill :SEGV, 0 $stderr.puts "but I carry on as usual" require 'dl' memory = DL::malloc 1 4096.times { |i| memory[0] = 42.chr * i } $stderr.puts "even genuine segfaults don't phase me" produces: segfault triggered but I carry on as usual
  • 7. maybe with some tenderlove require 'dl' require ‘neversaydie’ memory = DL::malloc 1 4096.times do |i| begin puts "#{i} : #{(memory[1] = 42.chr * i).length}" rescue NeverSayDie => e $stderr.puts "even genuine segfaults don't phase me" break end end produces: even genuine segfaults don't phase me
  • 8. but what I really want require 'dl' SIGSEGV = DL::dlopen('libsigsegv.dylib') install_handler = SIGSEGV['sigsegv_install_handler', 'IP'] deinstall_handler = SIGSEGV['sigsegv_deinstall_handler', '0'] leave_handler = SIGSEGV['sigsegv_leave_handler', 'IPPPP'] continuation = DL.callback('IPPP') do |address, b, c| raise RuntimeError, "segfault at #{address}" end handler = DL.callback('IPI') do |fault_address, serious| leave_handler.call continuation, fault_address, nil, nil end install_handler.call handler
  • 9. further reading http://www.jbrowse.com/text/rdl_en.html http://www.ruby-lang.org/en/downloads/ http://slides.games-with-brains.net/