SlideShare a Scribd company logo
1 of 53
Download to read offline
Sinatra:
    The Framework Within



    Aaron Quint / Quirkey NYC, LLC
                    /

    Ruby Kaigi / July 18, 2009


Friday, July 31, 2009
Brooklyn, New York

Friday, July 31, 2009
Sinatra.




Friday, July 31, 2009
I didn’t write Sinatra,
                                         …
                            I just love it.



Friday, July 31, 2009
Sinatra.

     require 'sinatra'

     get '/' do
       "Don't you hate pants?"
     end




Friday, July 31, 2009
Sinatra.




Friday, July 31, 2009
Sinatra.


     require 'sinatra'

     get '/homer/hate/:hate' do
       "Don't you hate #{params[:hate]}?"
     end




Friday, July 31, 2009
Sinatra.




Friday, July 31, 2009
Sinatra.

     require 'sinatra'

     get '/homer/hate/:hate.json' do
       content_type 'json'
       "{'hate': '#{params[:hate]}'}"
     end

     get '/homer/hate/:hate' do
       "Don't you hate #{params[:hate]}?"
     end

Friday, July 31, 2009
Classy.




Friday, July 31, 2009
Sinatra. Classy.
     require 'sinatra'
     require 'rack/flash'

     class ClassyApp < Sinatra::Default
       set :sessions, true
       use Rack::Flash

          get '/' do
            haml :index
          end

          post '/classify' do
            flash[:message] = 'Your text has been classified.'
            @text = "I do say, #{params[:text]}. Quite!"
            haml :classify
          end

     end

Friday, July 31, 2009
Sinatra. Classy.




Friday, July 31, 2009
Sinatra. Classy.




Friday, July 31, 2009
Sinatra
                             is not
                        a framework.



Friday, July 31, 2009
Framework.




Friday, July 31, 2009
Not a Framework.




Friday, July 31, 2009
Sinatra.




Friday, July 31, 2009
Not MVC.




Friday, July 31, 2009
WDNNSP
                        (We Don’t Need No Stinkin’ Pattern)




Friday, July 31, 2009
Sinatra
                           is a
                        library.



Friday, July 31, 2009
Sinatra as a library.

     ‣A DSL for defining routes.
     ‣                        DSL

     ‣A nicer Rack.
     ‣           Rack



Friday, July 31, 2009
Friday, July 31, 2009
Code first.

                        Then Sinatra.
                          Sinatra


Friday, July 31, 2009
My Awesome
                          Ruby Project.

                        Ruby
                                 Includes Sinatra.
                               Sinatra




Friday, July 31, 2009
Sinatra!




Friday, July 31, 2009
HTTP as
                           a language.
                        HTTP



Friday, July 31, 2009
Sinatra
                            speaks HTTP.
                        Sinatra HTTP



Friday, July 31, 2009
Do you speak HTTP?
                             HTTP



Friday, July 31, 2009
GET!




Friday, July 31, 2009
RESPONSE!




Friday, July 31, 2009
User        Rack
                        RestClient   Sinatra




Friday, July 31, 2009
Friday, July 31, 2009
The power of
                        the local web.
                               Web



Friday, July 31, 2009
The power of
                         localhost.




Friday, July 31, 2009
Friday, July 31, 2009
Friday, July 31, 2009
CALLING ALL
                        DEVELOPERS!




Friday, July 31, 2009
CALLING ALL
                        DEVELOPERS!
                         require 'sinatra'




Friday, July 31, 2009
CALLING ALL DEVELOPERS!




                        Awesome
                         Codes.




Friday, July 31, 2009
CALLING ALL DEVELOPERS!




                        Sinatra!




Friday, July 31, 2009
CALLING ALL DEVELOPERS!
     require 'sinatra'

     module MyProject
       class App < ::Sinatra::Default

               set :root, File.join(File.dirname(__FILE__), '..', '..')
               set :app_file, __FILE__
               #...

         get '/' do
           # ... SOMETHING AWESOME
         end
         # ...
       end
     end


Friday, July 31, 2009
CALLING ALL DEVELOPERS!




Friday, July 31, 2009
CALLING ALL DEVELOPERS!



                        Sinatra!




Friday, July 31, 2009
require 'sinatra'

   module Gembox


    CALLING ALL DEVELOPERS!
     class App < ::Sinatra::Default
       include Gembox::ViewHelpers
       include WillPaginate::ViewHelpers

          @@root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))

          set :root, @@root
          set :app_file, __FILE__

          before do
            Gembox::Gems.load
            @gems = Gembox::Gems.local_gems.paginate :page => params[:page], :per_page => 30
            @stats = Gembox::Gems.stats
          end

          #...
          get '/' do
            redirect '/gems'
          end

          get %r{/gems/doc/([w-_]+)/?([d.]+)?/?(.*)?} do
            #...
          end

          get %r{/gems/([w-_]+)/?([d.]+)?/?} do
            # ...
            haml :gem, :layout => show_layout
          end

          get '/gems/?' do
            # ...
            haml "gems_#{@show_as}".to_sym, :layout => show_layout
          end
Friday, July 31, 2009
Introducing




Friday, July 31, 2009
Super
                          Simple
                              Sinatra
                        Starter.

Friday, July 31, 2009
Vegas

     #!/usr/bin/env ruby

     require File.expand_path(File.dirname(__FILE__) +
                         "/../lib/gembox")
     require 'vegas'

     Vegas::Runner.new(Gembox::App, 'gembox')




Friday, July 31, 2009
Vegas

     [11:05 PM:~] $ gembox -h
     Usage: gembox [options]

     Vegas       options:
       -s,       --server SERVER     serve using SERVER (webrick/mongrel)
       -o,       --host HOST         listen on HOST (default: 0.0.0.0)
       -p,       --port PORT         use PORT (default: 5678)
       -e,       --env ENVIRONMENT   use ENVIRONMENT for defaults (default: development)
       -F,       --foreground        don't daemonize, run in the foreground
       -K,       --kill              kill the running process and exit
       -S,       --status            display the current running PID and URL then quit

     Common options:
       -h, --help                    Show this message
           --version                 Show version




Friday, July 31, 2009
Vegas
    $ sudo gem install gembox




Friday, July 31, 2009
Vegas
    $ sudo gem install neerajdotname-javascript_lab




Friday, July 31, 2009
The FUTURE!

    ‣Gems+Vegas as a distribution platform.
    ‣
    ‣Even easier workflow for mounting.
    ‣
    ‣Vegas as the central brain.
    ‣Vegas
    ‣Distribute tasks across the local network.
    ‣

Friday, July 31, 2009
Thank you!
     Thanks to Sougo Tsuboi, Leonard
      Chin and the other Ruby Kaigi
                Volunteers


Friday, July 31, 2009
Av
                                                                  ai
                                                                  la
                                                                      bl
                                                                        e
                                                                       fo
                                                                        rh
                                                                            ire
                                                                             !
                                    Aaron Quint
                                aaron@quirkey.com

                              http://www.quirkey.com

                        All code available and open source at:

                          http://code.quirkey.com/vegas
                         http://code.quirkey.com/gembox


Friday, July 31, 2009

More Related Content

Similar to Aaron Quint - Ruby Kaigi Presentation

Welcome and Introduction
Welcome and IntroductionWelcome and Introduction
Welcome and IntroductionESUG
 
Rj Auburn's Presentation at Emerging Communication Conference & Awards 2009 E...
Rj Auburn's Presentation at Emerging Communication Conference & Awards 2009 E...Rj Auburn's Presentation at Emerging Communication Conference & Awards 2009 E...
Rj Auburn's Presentation at Emerging Communication Conference & Awards 2009 E...eCommConf
 
Prototype & Scriptaculous
Prototype  & ScriptaculousPrototype  & Scriptaculous
Prototype & ScriptaculousThomas Fuchs
 
Oxente on Rails 2009
Oxente on Rails 2009Oxente on Rails 2009
Oxente on Rails 2009Fabio Akita
 
Wave Presentation
Wave PresentationWave Presentation
Wave Presentationbedney
 

Similar to Aaron Quint - Ruby Kaigi Presentation (6)

Welcome and Introduction
Welcome and IntroductionWelcome and Introduction
Welcome and Introduction
 
Rj Auburn's Presentation at Emerging Communication Conference & Awards 2009 E...
Rj Auburn's Presentation at Emerging Communication Conference & Awards 2009 E...Rj Auburn's Presentation at Emerging Communication Conference & Awards 2009 E...
Rj Auburn's Presentation at Emerging Communication Conference & Awards 2009 E...
 
Prototype & Scriptaculous
Prototype  & ScriptaculousPrototype  & Scriptaculous
Prototype & Scriptaculous
 
Oxente on Rails 2009
Oxente on Rails 2009Oxente on Rails 2009
Oxente on Rails 2009
 
Perl Critic In Depth
Perl Critic In DepthPerl Critic In Depth
Perl Critic In Depth
 
Wave Presentation
Wave PresentationWave Presentation
Wave Presentation
 

Recently uploaded

Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkPixlogix Infotech
 
React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...Karmanjay Verma
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Français Patch Tuesday - Avril
Français Patch Tuesday - AvrilFrançais Patch Tuesday - Avril
Français Patch Tuesday - AvrilIvanti
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesBernd Ruecker
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
Infrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platformsInfrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platformsYoss Cohen
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observabilityitnewsafrica
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
QMMS Lesson 2 - Using MS Excel Formula.pdf
QMMS Lesson 2 - Using MS Excel Formula.pdfQMMS Lesson 2 - Using MS Excel Formula.pdf
QMMS Lesson 2 - Using MS Excel Formula.pdfROWELL MARQUINA
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Digital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentDigital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentMahmoud Rabie
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditSkynet Technologies
 

Recently uploaded (20)

Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App Framework
 
React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Français Patch Tuesday - Avril
Français Patch Tuesday - AvrilFrançais Patch Tuesday - Avril
Français Patch Tuesday - Avril
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architectures
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
Infrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platformsInfrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platforms
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
QMMS Lesson 2 - Using MS Excel Formula.pdf
QMMS Lesson 2 - Using MS Excel Formula.pdfQMMS Lesson 2 - Using MS Excel Formula.pdf
QMMS Lesson 2 - Using MS Excel Formula.pdf
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Digital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentDigital Tools & AI in Career Development
Digital Tools & AI in Career Development
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance Audit
 

Aaron Quint - Ruby Kaigi Presentation

  • 1. Sinatra: The Framework Within Aaron Quint / Quirkey NYC, LLC / Ruby Kaigi / July 18, 2009 Friday, July 31, 2009
  • 4. I didn’t write Sinatra, … I just love it. Friday, July 31, 2009
  • 5. Sinatra. require 'sinatra' get '/' do "Don't you hate pants?" end Friday, July 31, 2009
  • 7. Sinatra. require 'sinatra' get '/homer/hate/:hate' do "Don't you hate #{params[:hate]}?" end Friday, July 31, 2009
  • 9. Sinatra. require 'sinatra' get '/homer/hate/:hate.json' do content_type 'json' "{'hate': '#{params[:hate]}'}" end get '/homer/hate/:hate' do "Don't you hate #{params[:hate]}?" end Friday, July 31, 2009
  • 11. Sinatra. Classy. require 'sinatra' require 'rack/flash' class ClassyApp < Sinatra::Default set :sessions, true use Rack::Flash get '/' do haml :index end post '/classify' do flash[:message] = 'Your text has been classified.' @text = "I do say, #{params[:text]}. Quite!" haml :classify end end Friday, July 31, 2009
  • 14. Sinatra is not a framework. Friday, July 31, 2009
  • 16. Not a Framework. Friday, July 31, 2009
  • 19. WDNNSP (We Don’t Need No Stinkin’ Pattern) Friday, July 31, 2009
  • 20. Sinatra is a library. Friday, July 31, 2009
  • 21. Sinatra as a library. ‣A DSL for defining routes. ‣ DSL ‣A nicer Rack. ‣ Rack Friday, July 31, 2009
  • 23. Code first. Then Sinatra. Sinatra Friday, July 31, 2009
  • 24. My Awesome Ruby Project. Ruby Includes Sinatra. Sinatra Friday, July 31, 2009
  • 26. HTTP as a language. HTTP Friday, July 31, 2009
  • 27. Sinatra speaks HTTP. Sinatra HTTP Friday, July 31, 2009
  • 28. Do you speak HTTP? HTTP Friday, July 31, 2009
  • 31. User Rack RestClient Sinatra Friday, July 31, 2009
  • 33. The power of the local web. Web Friday, July 31, 2009
  • 34. The power of localhost. Friday, July 31, 2009
  • 37. CALLING ALL DEVELOPERS! Friday, July 31, 2009
  • 38. CALLING ALL DEVELOPERS! require 'sinatra' Friday, July 31, 2009
  • 39. CALLING ALL DEVELOPERS! Awesome Codes. Friday, July 31, 2009
  • 40. CALLING ALL DEVELOPERS! Sinatra! Friday, July 31, 2009
  • 41. CALLING ALL DEVELOPERS! require 'sinatra' module MyProject class App < ::Sinatra::Default set :root, File.join(File.dirname(__FILE__), '..', '..') set :app_file, __FILE__ #... get '/' do # ... SOMETHING AWESOME end # ... end end Friday, July 31, 2009
  • 43. CALLING ALL DEVELOPERS! Sinatra! Friday, July 31, 2009
  • 44. require 'sinatra' module Gembox CALLING ALL DEVELOPERS! class App < ::Sinatra::Default include Gembox::ViewHelpers include WillPaginate::ViewHelpers @@root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')) set :root, @@root set :app_file, __FILE__ before do Gembox::Gems.load @gems = Gembox::Gems.local_gems.paginate :page => params[:page], :per_page => 30 @stats = Gembox::Gems.stats end #... get '/' do redirect '/gems' end get %r{/gems/doc/([w-_]+)/?([d.]+)?/?(.*)?} do #... end get %r{/gems/([w-_]+)/?([d.]+)?/?} do # ... haml :gem, :layout => show_layout end get '/gems/?' do # ... haml "gems_#{@show_as}".to_sym, :layout => show_layout end Friday, July 31, 2009
  • 46. Super Simple Sinatra Starter. Friday, July 31, 2009
  • 47. Vegas #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + "/../lib/gembox") require 'vegas' Vegas::Runner.new(Gembox::App, 'gembox') Friday, July 31, 2009
  • 48. Vegas [11:05 PM:~] $ gembox -h Usage: gembox [options] Vegas options: -s, --server SERVER serve using SERVER (webrick/mongrel) -o, --host HOST listen on HOST (default: 0.0.0.0) -p, --port PORT use PORT (default: 5678) -e, --env ENVIRONMENT use ENVIRONMENT for defaults (default: development) -F, --foreground don't daemonize, run in the foreground -K, --kill kill the running process and exit -S, --status display the current running PID and URL then quit Common options: -h, --help Show this message --version Show version Friday, July 31, 2009
  • 49. Vegas $ sudo gem install gembox Friday, July 31, 2009
  • 50. Vegas $ sudo gem install neerajdotname-javascript_lab Friday, July 31, 2009
  • 51. The FUTURE! ‣Gems+Vegas as a distribution platform. ‣ ‣Even easier workflow for mounting. ‣ ‣Vegas as the central brain. ‣Vegas ‣Distribute tasks across the local network. ‣ Friday, July 31, 2009
  • 52. Thank you! Thanks to Sougo Tsuboi, Leonard Chin and the other Ruby Kaigi Volunteers Friday, July 31, 2009
  • 53. Av ai la bl e fo rh ire ! Aaron Quint aaron@quirkey.com http://www.quirkey.com All code available and open source at: http://code.quirkey.com/vegas http://code.quirkey.com/gembox Friday, July 31, 2009