SlideShare uma empresa Scribd logo
1 de 27
Baixar para ler offline
Reusing your frontend JS
on the server with V8/Rhino
Pushing SRP & DI/IoC to whole new level
Kenneth Kalmer

Chief Rocket Scientist @ ValuationUP.com
@kennethkalmer
github/kennethkalmer
www.opensourcery.co.za

 kennethkalmer
ValuationUP.com

 Help entrepreneurs make REAL sense of their
 management accounts
 Comparative analysis within industry
 Refactoring financials by getting from red to green
 Take actions to increase their valuations
 Valuation is the ultimate metric
The challenge


We need a very responsive UI
Realtime updates as the user inputs information
The RTT to the server is not worth the wait for such a
simple formula
Done!


Repeat that for 50+ financial models
Build fully buzzword compliant frontend
Panic!

 Let’s offer a PDF with all the information


 A PDF...
 ...WITH ALL THE INFORMATION
We did it!
But how?
Dilemma


Duplicate?
Reuse?
wkhtmltopdf? (a.k.a. wtftopdf)
Reuse!


Single Responsibility Principle
Dependency Injection/Inversion on Control
Use as much JS on the server as possible, where
possible!
By using
  therubyracer (github.com/cowboyd/rubyracer)
  therubyrhino (github.com/cowboyd/rubyrhino)
  coffee-script


1 gem 'therubyracer', platforms: :ruby
2 gem 'therubyrhino', platforms: :jruby
3
4 gem 'coffee-script'
That’s WACC!
With coffee
 1 # Determine the WACC of the business (weighted average cost of capital)
 2 class Demo.WACC
 3
 4   constructor: (statement) ->
 5     @statement = statement
 6
 7     @cost_of_equity = statement.cost_of_equity
 8     unless _.isFinite( @cost_of_equity )
 9       @cost_of_equity = 0.30
10
11   calculate: ->
12
13     e = ( @statement.equity / ( @statement.debt + @statement.equity ) ) * @cost_of_equity
14     d = ( @statement.debt / ( @statement.debt + @statement.equity ) ) * @statement.costOfDebt
15     t = ( 1 - @statement.taxRate )
16
17     e + d * t
18
19   # Return the calculated WACC
20   value: ->
21     @wacc or= @calculate()
Present it

 1 class Demo.WaccLayout
 2
 3   # The view that will render our information
 4   view: null
 5
 6   initialize: (data, view = null) ->
 7     @data = data
 8     @view = view
 9
10   render: ->
11     wacc = new Demo.WACC( @data.statement )
12
13     @view.render( wacc: wacc.value() )
Client-side view & usage
 1   # Simple backbone view
 2   class Demo.WaccView extends Backbone.View
 3
 4     render: (options) ->
 5       wacc = options.wacc
 6
 7       @$el.empty().append( "<h1>#{wacc}</h1>" )
 8
 9
10
11
12
13   # Initialize a view
14   view = new Demo.WaccView( el: '#wacc' )
15
16   # Load and render our layout
17   layout = new Demo.WaccLayout( view: view, data: data )
18   layout.render()
Reuse on the server...
JavaScript Context
 1   require 'v8'
 2   # require 'rhino'
 3
 4   # This service wraps a JS context and allows us to interact with our Javascript
 5   # directly in Ruby.
 6   class Javascript
 7
 8     # Our V8 context object
 9     attr_reader :context
10
11     # Some delegations
12     delegate :load, :eval, :[], :[]=, to: :context
13
14     def initialize()
15       @context = V8::Context.new
16       #@context = Rhino::Context.new
17
18         # Setup a fake 'window' object
19         @context['window'] = FakeWindow.new( @context )
20         @context['console'] = FakeConsole.new
21
22       # Load our global setup
23       load_coffee Rails.root.join( 'app/assets/javascripts/setup.js.coffee' )
24     end
25
26     # truncated, lots more detracting stuff down below...
27
28   end
CoffeeScript sprinkles


1 # Compile and load a CoffeeScript file into the current context
2 def load_coffee( path )
3   compiled_coffeescript = CoffeeScript.compile( File.read( path ) )
4   context.eval compiled_coffeescript
5 end
Pause

We have a JavaScript context (V8) at our finger tips
Have some basic CoffeeScript loading abilities
And some additional plumbing
Far from a DOM
Server-side wrapper
 1 class WaccLayout
 2
 3   def initialize( view, context = Javascript.new )
 4     @context = context
 5
 6     load_dependencies
 7
 8     # Pass our Ruby view into the context
 9     @context["view"] = view
10
11     # Setup
12     @context.eval <<-EOJS
13     var layout = new Demo.WaccLayout({
14       view: view, data: data
15     });
16     EOJS
17   end
18
19   def render
20     context['layout']['render'].methodcall( context['layout'] )
21   end
22
23   def load_dependencies
24     @context.load_coffee Rails.root.join("app/assets/javascripts/wacc.js.coffee")
25     @context.load_coffee Rails.root.join("app/assets/javascripts/wacc_layout.js.coffee")
26   end
27 end
Server-side view & usage
 1   class WaccPdf
 2
 3     def initialize
 4       @pdf = Prawn::Document.new
 5     end
 6
 7     def render( options )
 8       wacc = options.wacc
 9
10       @pdf.text "WACC: #{wacc}"
11     end
12
13   end
14
15
16   # Setup a view
17   view = WaccPdf.new
18
19   # Setup a layout and render
20   layout = WaccLayout.new( view )
21   layout.render
1,000 ft view
Reminder why we did it?
Yes please!

 https://github.com/kennethkalmer/rubyfuza-2013
 https://rubyfuza-2013-wacc.herokuapp.com


 Later this weekend, you’re all getting drunk tonight
 anyway!!
Thank you!
It’s been wild!

Mais conteúdo relacionado

Mais procurados

Mais procurados (20)

Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018
 
Reduxing like a pro
Reduxing like a proReduxing like a pro
Reduxing like a pro
 
Intelligent infrastructure with SaltStack
Intelligent infrastructure with SaltStackIntelligent infrastructure with SaltStack
Intelligent infrastructure with SaltStack
 
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java GirlFull-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
 
Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019
Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019
Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019
 
Things I Heart
Things I HeartThings I Heart
Things I Heart
 
Remote Config REST API and Versioning
Remote Config REST API and VersioningRemote Config REST API and Versioning
Remote Config REST API and Versioning
 
Windows Server AppFabric
Windows Server AppFabricWindows Server AppFabric
Windows Server AppFabric
 
Sockets and rails
Sockets and railsSockets and rails
Sockets and rails
 
Using redux
Using reduxUsing redux
Using redux
 
Designing applications with Redux
Designing applications with ReduxDesigning applications with Redux
Designing applications with Redux
 
Building with Firebase
Building with FirebaseBuilding with Firebase
Building with Firebase
 
Where is my scalable api?
Where is my scalable api?Where is my scalable api?
Where is my scalable api?
 
1時間で作るマッシュアップサービス(関西版)
1時間で作るマッシュアップサービス(関西版)1時間で作るマッシュアップサービス(関西版)
1時間で作るマッシュアップサービス(関西版)
 
SignalR: Above & Beyond Chat
SignalR: Above & Beyond ChatSignalR: Above & Beyond Chat
SignalR: Above & Beyond Chat
 
React state management with Redux and MobX
React state management with Redux and MobXReact state management with Redux and MobX
React state management with Redux and MobX
 
A Series of Fortunate Events: Building an Operator in Java
A Series of Fortunate Events: Building an Operator in JavaA Series of Fortunate Events: Building an Operator in Java
A Series of Fortunate Events: Building an Operator in Java
 
Curing Webpack Cancer
Curing Webpack CancerCuring Webpack Cancer
Curing Webpack Cancer
 
Neoito — React 101
Neoito — React 101Neoito — React 101
Neoito — React 101
 
Micrometerでメトリクスを収集してAmazon CloudWatchで可視化
Micrometerでメトリクスを収集してAmazon CloudWatchで可視化Micrometerでメトリクスを収集してAmazon CloudWatchで可視化
Micrometerでメトリクスを収集してAmazon CloudWatchで可視化
 

Destaque (6)

Daemon Kit - RubyKaigi 2009
Daemon Kit - RubyKaigi 2009Daemon Kit - RubyKaigi 2009
Daemon Kit - RubyKaigi 2009
 
Broken Dreams & Shattered Promises
Broken Dreams & Shattered PromisesBroken Dreams & Shattered Promises
Broken Dreams & Shattered Promises
 
Why ruby
Why rubyWhy ruby
Why ruby
 
Unleashing the Rails Asset Pipeline
Unleashing the Rails Asset PipelineUnleashing the Rails Asset Pipeline
Unleashing the Rails Asset Pipeline
 
Ruote
RuoteRuote
Ruote
 
Ruote: A Ruby workflow engine
Ruote:  A Ruby workflow engineRuote:  A Ruby workflow engine
Ruote: A Ruby workflow engine
 

Semelhante a Reusing your frontend JS on the server with V8/Rhino

Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Paulo Ragonha
 
Functional Web Development
Functional Web DevelopmentFunctional Web Development
Functional Web Development
FITC
 

Semelhante a Reusing your frontend JS on the server with V8/Rhino (20)

Rails 6 frontend frameworks
Rails 6 frontend frameworksRails 6 frontend frameworks
Rails 6 frontend frameworks
 
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Jsf intro
Jsf introJsf intro
Jsf intro
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSAn intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECS
 
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
 
SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!
 
JavaFX Enterprise (JavaOne 2014)
JavaFX Enterprise (JavaOne 2014)JavaFX Enterprise (JavaOne 2014)
JavaFX Enterprise (JavaOne 2014)
 
Serverless and React
Serverless and ReactServerless and React
Serverless and React
 
BOF2644 Developing Java EE 7 Scala apps
BOF2644 Developing Java EE 7 Scala appsBOF2644 Developing Java EE 7 Scala apps
BOF2644 Developing Java EE 7 Scala apps
 
Introducing Vuex in your project
Introducing Vuex in your projectIntroducing Vuex in your project
Introducing Vuex in your project
 
State manager in Vue.js, from zero to Vuex
State manager in Vue.js, from zero to VuexState manager in Vue.js, from zero to Vuex
State manager in Vue.js, from zero to Vuex
 
Apollo. The client we deserve
Apollo. The client we deserveApollo. The client we deserve
Apollo. The client we deserve
 
Functional Web Development
Functional Web DevelopmentFunctional Web Development
Functional Web Development
 
Real World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS ApplicationReal World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS Application
 
React, Flux and a little bit of Redux
React, Flux and a little bit of ReduxReact, Flux and a little bit of Redux
React, Flux and a little bit of Redux
 
Camel on Cloud by Christina Lin
Camel on Cloud by Christina LinCamel on Cloud by Christina Lin
Camel on Cloud by Christina Lin
 
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
 
APIs, APIs Everywhere!
APIs, APIs Everywhere!APIs, APIs Everywhere!
APIs, APIs Everywhere!
 
Rack
RackRack
Rack
 

Último

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 
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
vu2urc
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
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
giselly40
 

Último (20)

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
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
 
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
 
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
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
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
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
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
 
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
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 

Reusing your frontend JS on the server with V8/Rhino

  • 1. Reusing your frontend JS on the server with V8/Rhino Pushing SRP & DI/IoC to whole new level
  • 2. Kenneth Kalmer Chief Rocket Scientist @ ValuationUP.com @kennethkalmer github/kennethkalmer www.opensourcery.co.za kennethkalmer
  • 3. ValuationUP.com Help entrepreneurs make REAL sense of their management accounts Comparative analysis within industry Refactoring financials by getting from red to green Take actions to increase their valuations Valuation is the ultimate metric
  • 4. The challenge We need a very responsive UI Realtime updates as the user inputs information The RTT to the server is not worth the wait for such a simple formula
  • 5.
  • 6. Done! Repeat that for 50+ financial models Build fully buzzword compliant frontend
  • 7. Panic! Let’s offer a PDF with all the information A PDF... ...WITH ALL THE INFORMATION
  • 8.
  • 11. Reuse! Single Responsibility Principle Dependency Injection/Inversion on Control Use as much JS on the server as possible, where possible!
  • 12. By using therubyracer (github.com/cowboyd/rubyracer) therubyrhino (github.com/cowboyd/rubyrhino) coffee-script 1 gem 'therubyracer', platforms: :ruby 2 gem 'therubyrhino', platforms: :jruby 3 4 gem 'coffee-script'
  • 14. With coffee 1 # Determine the WACC of the business (weighted average cost of capital) 2 class Demo.WACC 3 4 constructor: (statement) -> 5 @statement = statement 6 7 @cost_of_equity = statement.cost_of_equity 8 unless _.isFinite( @cost_of_equity ) 9 @cost_of_equity = 0.30 10 11 calculate: -> 12 13 e = ( @statement.equity / ( @statement.debt + @statement.equity ) ) * @cost_of_equity 14 d = ( @statement.debt / ( @statement.debt + @statement.equity ) ) * @statement.costOfDebt 15 t = ( 1 - @statement.taxRate ) 16 17 e + d * t 18 19 # Return the calculated WACC 20 value: -> 21 @wacc or= @calculate()
  • 15. Present it 1 class Demo.WaccLayout 2 3 # The view that will render our information 4 view: null 5 6 initialize: (data, view = null) -> 7 @data = data 8 @view = view 9 10 render: -> 11 wacc = new Demo.WACC( @data.statement ) 12 13 @view.render( wacc: wacc.value() )
  • 16. Client-side view & usage 1 # Simple backbone view 2 class Demo.WaccView extends Backbone.View 3 4 render: (options) -> 5 wacc = options.wacc 6 7 @$el.empty().append( "<h1>#{wacc}</h1>" ) 8 9 10 11 12 13 # Initialize a view 14 view = new Demo.WaccView( el: '#wacc' ) 15 16 # Load and render our layout 17 layout = new Demo.WaccLayout( view: view, data: data ) 18 layout.render()
  • 17. Reuse on the server...
  • 18. JavaScript Context 1 require 'v8' 2 # require 'rhino' 3 4 # This service wraps a JS context and allows us to interact with our Javascript 5 # directly in Ruby. 6 class Javascript 7 8 # Our V8 context object 9 attr_reader :context 10 11 # Some delegations 12 delegate :load, :eval, :[], :[]=, to: :context 13 14 def initialize() 15 @context = V8::Context.new 16 #@context = Rhino::Context.new 17 18 # Setup a fake 'window' object 19 @context['window'] = FakeWindow.new( @context ) 20 @context['console'] = FakeConsole.new 21 22 # Load our global setup 23 load_coffee Rails.root.join( 'app/assets/javascripts/setup.js.coffee' ) 24 end 25 26 # truncated, lots more detracting stuff down below... 27 28 end
  • 19. CoffeeScript sprinkles 1 # Compile and load a CoffeeScript file into the current context 2 def load_coffee( path ) 3 compiled_coffeescript = CoffeeScript.compile( File.read( path ) ) 4 context.eval compiled_coffeescript 5 end
  • 20. Pause We have a JavaScript context (V8) at our finger tips Have some basic CoffeeScript loading abilities And some additional plumbing Far from a DOM
  • 21. Server-side wrapper 1 class WaccLayout 2 3 def initialize( view, context = Javascript.new ) 4 @context = context 5 6 load_dependencies 7 8 # Pass our Ruby view into the context 9 @context["view"] = view 10 11 # Setup 12 @context.eval <<-EOJS 13 var layout = new Demo.WaccLayout({ 14 view: view, data: data 15 }); 16 EOJS 17 end 18 19 def render 20 context['layout']['render'].methodcall( context['layout'] ) 21 end 22 23 def load_dependencies 24 @context.load_coffee Rails.root.join("app/assets/javascripts/wacc.js.coffee") 25 @context.load_coffee Rails.root.join("app/assets/javascripts/wacc_layout.js.coffee") 26 end 27 end
  • 22. Server-side view & usage 1 class WaccPdf 2 3 def initialize 4 @pdf = Prawn::Document.new 5 end 6 7 def render( options ) 8 wacc = options.wacc 9 10 @pdf.text "WACC: #{wacc}" 11 end 12 13 end 14 15 16 # Setup a view 17 view = WaccPdf.new 18 19 # Setup a layout and render 20 layout = WaccLayout.new( view ) 21 layout.render
  • 24. Reminder why we did it?
  • 25.
  • 26. Yes please! https://github.com/kennethkalmer/rubyfuza-2013 https://rubyfuza-2013-wacc.herokuapp.com Later this weekend, you’re all getting drunk tonight anyway!!