gina-conveyor 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/.gitignore +9 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +49 -0
  4. data/LICENSE +25 -0
  5. data/README.md +24 -0
  6. data/Rakefile +2 -0
  7. data/bin/conveyor +4 -0
  8. data/conveyor.gemspec +30 -0
  9. data/lib/conveyor/belt.rb +59 -0
  10. data/lib/conveyor/foreman.rb +182 -0
  11. data/lib/conveyor/input/commands.rb +21 -0
  12. data/lib/conveyor/input/console.rb +39 -0
  13. data/lib/conveyor/input.rb +12 -0
  14. data/lib/conveyor/job_state.rb +2 -0
  15. data/lib/conveyor/output/channel.rb +22 -0
  16. data/lib/conveyor/output/console.rb +39 -0
  17. data/lib/conveyor/output/email.rb +36 -0
  18. data/lib/conveyor/output/logfile.rb +38 -0
  19. data/lib/conveyor/output.rb +76 -0
  20. data/lib/conveyor/queue.rb +80 -0
  21. data/lib/conveyor/status.rb +29 -0
  22. data/lib/conveyor/version.rb +3 -0
  23. data/lib/conveyor/websocket.rb +37 -0
  24. data/lib/conveyor/worker.rb +120 -0
  25. data/lib/conveyor/workers/syntax.rb +127 -0
  26. data/lib/conveyor.rb +62 -0
  27. data/webviewer/.gitignore +15 -0
  28. data/webviewer/Gemfile +39 -0
  29. data/webviewer/Gemfile.lock +119 -0
  30. data/webviewer/README.rdoc +261 -0
  31. data/webviewer/Rakefile +7 -0
  32. data/webviewer/app/assets/images/rails.png +0 -0
  33. data/webviewer/app/assets/javascripts/application.js +16 -0
  34. data/webviewer/app/assets/javascripts/welcome.js.coffee +61 -0
  35. data/webviewer/app/assets/stylesheets/application.css.scss +6 -0
  36. data/webviewer/app/assets/stylesheets/welcome.css.scss +3 -0
  37. data/webviewer/app/controllers/application_controller.rb +3 -0
  38. data/webviewer/app/controllers/welcome_controller.rb +4 -0
  39. data/webviewer/app/helpers/application_helper.rb +2 -0
  40. data/webviewer/app/helpers/welcome_helper.rb +2 -0
  41. data/webviewer/app/mailers/.gitkeep +0 -0
  42. data/webviewer/app/models/.gitkeep +0 -0
  43. data/webviewer/app/views/layouts/application.html.haml +14 -0
  44. data/webviewer/app/views/welcome/index.html.haml +3 -0
  45. data/webviewer/config/application.rb +59 -0
  46. data/webviewer/config/boot.rb +6 -0
  47. data/webviewer/config/database.yml +25 -0
  48. data/webviewer/config/environment.rb +5 -0
  49. data/webviewer/config/environments/development.rb +37 -0
  50. data/webviewer/config/environments/production.rb +67 -0
  51. data/webviewer/config/environments/test.rb +37 -0
  52. data/webviewer/config/initializers/backtrace_silencers.rb +7 -0
  53. data/webviewer/config/initializers/inflections.rb +15 -0
  54. data/webviewer/config/initializers/mime_types.rb +5 -0
  55. data/webviewer/config/initializers/secret_token.rb +7 -0
  56. data/webviewer/config/initializers/session_store.rb +8 -0
  57. data/webviewer/config/initializers/wrap_parameters.rb +14 -0
  58. data/webviewer/config/locales/en.yml +5 -0
  59. data/webviewer/config/routes.rb +58 -0
  60. data/webviewer/config.ru +4 -0
  61. data/webviewer/db/seeds.rb +7 -0
  62. data/webviewer/doc/README_FOR_APP +2 -0
  63. data/webviewer/lib/assets/.gitkeep +0 -0
  64. data/webviewer/lib/tasks/.gitkeep +0 -0
  65. data/webviewer/log/.gitkeep +0 -0
  66. data/webviewer/public/404.html +26 -0
  67. data/webviewer/public/422.html +26 -0
  68. data/webviewer/public/500.html +25 -0
  69. data/webviewer/public/favicon.ico +0 -0
  70. data/webviewer/public/robots.txt +5 -0
  71. data/webviewer/script/rails +6 -0
  72. data/webviewer/test/fixtures/.gitkeep +0 -0
  73. data/webviewer/test/functional/.gitkeep +0 -0
  74. data/webviewer/test/functional/welcome_controller_test.rb +7 -0
  75. data/webviewer/test/integration/.gitkeep +0 -0
  76. data/webviewer/test/performance/browsing_test.rb +12 -0
  77. data/webviewer/test/test_helper.rb +13 -0
  78. data/webviewer/test/unit/.gitkeep +0 -0
  79. data/webviewer/test/unit/helpers/welcome_helper_test.rb +4 -0
  80. data/webviewer/vendor/assets/javascripts/.gitkeep +0 -0
  81. data/webviewer/vendor/assets/stylesheets/.gitkeep +0 -0
  82. data/webviewer/vendor/plugins/.gitkeep +0 -0
  83. data/worker-examples/barrow_webcam.worker.disabled +19 -0
  84. data/worker-examples/barrow_webcam.worker.example +16 -0
  85. data/worker-examples/conveyor.worker.example +5 -0
  86. data/worker-examples/devel.worker +17 -0
  87. metadata +260 -0
@@ -0,0 +1,80 @@
1
+ module Conveyor
2
+ class Queue
3
+ def initialize
4
+ @mutex = Mutex.new
5
+ @queue = []
6
+ end
7
+
8
+ def count
9
+ @queue.count
10
+ end
11
+
12
+ def touch(file)
13
+ push(file)
14
+ end
15
+
16
+ def push(file)
17
+ @mutex.synchronize do
18
+ i = @queue.find_index { |j| j[:file] == file }
19
+ if i.nil?
20
+ @queue.push({ :file => file, :updated_at => Time.now })
21
+ else
22
+ @queue[i][:updated_at] = Time.now
23
+ end
24
+ @queue.sort! { |x,y| x[:updated_at] <=> y[:updated_at] }
25
+ end
26
+ end
27
+
28
+ def reserve(file = nil)
29
+ @mutex.synchronize do
30
+ # find first non-reserved job
31
+ i = @queue.find_index { |j| !j[:reserved] }
32
+ @queue[i][:reserved] = true unless i.nil?
33
+ @queue[i] unless i.nil?
34
+ end
35
+ end
36
+
37
+ def unreserve(file)
38
+ @mutex.synchronize do
39
+ i = find_index(file)
40
+ @queue[i][:reserved] = false unless i.nil?
41
+ @queue[i] unless i.nil?
42
+ end
43
+ end
44
+
45
+ def find_index(file = nil)
46
+ if file.nil?
47
+ @queue.empty? ? nil : 0
48
+ else
49
+ @queue.find_index { |j| j[:file] == file }
50
+ end
51
+ end
52
+
53
+ def find(file)
54
+ i = find_index(file)
55
+ @queue[i] unless i.nil?
56
+ end
57
+
58
+ def unpop(job)
59
+ @mutex.synchronize do
60
+ unless find(job[:file])
61
+ @queue.push(job)
62
+ @queue.sort! { |x,y| x[:updated_at] <=> y[:updated_at] }
63
+ end
64
+ end
65
+ end
66
+
67
+ def pop(file = nil)
68
+ if file.nil?
69
+ @mutex.synchronize do
70
+ @queue.shift
71
+ end
72
+ else
73
+ @mutex.synchronize do
74
+ j = find(file)
75
+ @queue.delete(j)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,29 @@
1
+ module Conveyor
2
+ class Status
3
+ attr_reader :success
4
+ attr_accessor :errors
5
+ attr_reader :path
6
+
7
+ def initialize(path = nil)
8
+ reset!(path)
9
+ end
10
+
11
+ def reset!(path = nil)
12
+ @path = path
13
+ @success = true
14
+ @errors = []
15
+ end
16
+
17
+ def fail!(v = false)
18
+ @success &= v
19
+ end
20
+
21
+ def success!(v=true)
22
+ @success &= v
23
+ end
24
+
25
+ def success?
26
+ @success
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Conveyor
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,37 @@
1
+ module Conveyor
2
+ class Websocket
3
+ class << self
4
+ def start
5
+ if config[:disable]
6
+ fm.info "Websocket disabled"
7
+ return
8
+ end
9
+
10
+ fm.info "Starting websocket on #{config[:host]}:#{config[:port]}", :color => :green
11
+
12
+ EventMachine::start_server(config[:host], config[:port],
13
+ EventMachine::WebSocket::Connection, config) do |ws|
14
+ ws.onopen {
15
+ sid = fm.channel.subscribe { |type,msg| ws.send msg }
16
+ fm.info "#{sid} connected to websocket!"
17
+ ws.onclose {
18
+ fm.channel.unsubscribe(sid)
19
+ }
20
+ }
21
+ end
22
+ end
23
+
24
+ def stop
25
+ # EM::WebSocket.stop unless config[:disable]
26
+ end
27
+
28
+ def fm
29
+ Conveyor::Foreman.instance
30
+ end
31
+
32
+ def config
33
+ fm.config[:websocket]
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,120 @@
1
+ require 'rubygems'
2
+ require 'active_support/core_ext'
3
+ require 'open3'
4
+ require 'conveyor/workers/syntax'
5
+
6
+ module Conveyor
7
+ class Worker
8
+ include Conveyor::Output
9
+ include Conveyor::Workers::Syntax
10
+
11
+ attr_accessor :filename
12
+ attr_reader :status
13
+ attr_reader :worker_def
14
+
15
+ def initialize(file, worker_def, log = MSGLVLS[:debug])
16
+ @filename = file
17
+ @loglvl = log
18
+ @worker_def = worker_def
19
+ @notify = []
20
+ # @glob = escape_glob(glob)
21
+ end
22
+
23
+ # Return name to be used for logging purposes
24
+ def name(value=nil)
25
+ @name = value unless value.nil?
26
+ @name ||= File.basename(worker_def)
27
+ @name
28
+ end
29
+
30
+ # Default log file to be based on worker def name
31
+ def logfile
32
+ dir = File.dirname(worker_def)
33
+ File.expand_path(File.basename(worker_def, '.worker') + '.log', dir)
34
+ end
35
+
36
+ # Catch any calls to error and set the status fail flags
37
+ def error(*msg)
38
+ opts = msg.extract_options!
39
+ unless msg.flatten.empty?
40
+ @status.fail!
41
+ msg.unshift("Error encountered in #{worker_def}")
42
+ super(*msg, opts)
43
+ end
44
+ @status.success?
45
+ end
46
+
47
+ # Start the worker
48
+ def start
49
+ @status = Conveyor::Status.new(@filename)
50
+ info "Starting #{@filename}", :color => :green
51
+ @start = Time.now
52
+ begin
53
+ instance_eval(File.read(@worker_def), worker_def)
54
+ ensure
55
+ @elapsed = "%0.2f"%(Time.now - @start)
56
+
57
+ #Check status and send any errors we collected
58
+ if @status.success?
59
+ info "Completed #{@filename}, #{@elapsed}s elapsed", :color => :green
60
+ else
61
+ error "Error(s) encountered in #{@filename}", :color => :red
62
+ end
63
+ send_notifications
64
+ end
65
+ end
66
+
67
+ protected
68
+
69
+ def create_dirs_for_cmd(src, dest)
70
+ if src.is_a?(Array) || Array.wrap(src).count > 1 || dest.last == ?/
71
+ mkdir(dest)
72
+ else
73
+ mkdir(File.dirname(dest))
74
+ end
75
+ end
76
+
77
+ def verified_cmd(cmd, src, dest, &block)
78
+ create_dirs_for_cmd(src, dest)
79
+ dest = File.expand_path(dest)
80
+
81
+ Array.wrap(src).each do |s|
82
+ run "#{cmd} #{s} #{dest}"
83
+ sync
84
+
85
+ if block_given?
86
+ result = yield(s, dest)
87
+ @status.fail! unless result
88
+ end
89
+ end
90
+ end
91
+
92
+ def verified_move(src, dest)
93
+ verified_cmd(:mv, src, dest) do |src,dest|
94
+ verify_move(src,dest)
95
+ end
96
+ end
97
+
98
+ def verified_copy(src, dest)
99
+ verified_cmd(:cp, src, dest) do |src,dest|
100
+ verify_copy(src,dest)
101
+ end
102
+ end
103
+
104
+ def verify_copy(src, dest)
105
+ if File.directory? dest
106
+ File.exists?(File.join(dest, File.basename(src)))
107
+ else
108
+ File.exists?(dest)
109
+ end
110
+ end
111
+
112
+ def verify_move(src, dest)
113
+ if File.directory? dest
114
+ File.exists?(File.join(dest, File.basename(src))) && !File.exists?(src)
115
+ else
116
+ File.exists?(dest) && !File.exists?(src)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,127 @@
1
+ module Conveyor
2
+ module Workers
3
+ module Syntax
4
+
5
+ # Will return a string of any method returned that isn't handled
6
+ # ex: match extension txt => match(extension("foo"))
7
+ def method_missing(method, value = nil)
8
+ return method.to_s
9
+ end
10
+
11
+ # Returns a recursive file glob string for the passed in string
12
+ def file(glob)
13
+ "**/#{glob}"
14
+ end
15
+
16
+ # Returns an extension glob string for passed in string
17
+ def extension(glob)
18
+ "*.#{glob}"
19
+ end
20
+
21
+ # Returns a glob string that will match any file
22
+ def any
23
+ '*'
24
+ end
25
+
26
+ # Returns a list of files that have the same basename but different extension
27
+ # in the same directory
28
+ def like(name)
29
+ dir = File.dirname(name)
30
+ Dir.glob(File.join(dir, File.basename(name, '.*') + '.*'))
31
+ end
32
+
33
+ # Returns the filename of the file that triggered the job
34
+ def filename
35
+ @filename
36
+ end
37
+
38
+ # Which directories to watch for file change events.
39
+ def watch(*args, &block)
40
+ yield
41
+ end
42
+
43
+ # Match string/glob for the files that should trigger file change events
44
+ def match(glob, &block)
45
+ yield @filename
46
+ end
47
+
48
+ # Run the system sync command
49
+ def sync
50
+ run 'sync', :quiet => true
51
+ end
52
+
53
+ # Change current working directory, optionally takes a block
54
+ # NOTE: Consider removing this as it can cause problems with threaded workers
55
+ def chdir(dir, &block)
56
+ Dir.chdir(File.expand_path(dir), &block)
57
+ end
58
+
59
+ # Run the system command, and make sure that any errors are caught and returne
60
+ # up the status change
61
+ def run(*cmd)
62
+ opts = cmd.extract_options!
63
+ begin
64
+ info cmd.join(' ') unless opts[:quiet]
65
+ output,err,thr = Open3.capture3(Array.wrap(cmd).join(' '))
66
+ info output.chomp unless output.chomp.length == 0
67
+ if thr.success?
68
+ if err.chomp.length > 0
69
+ warning "Error output recieved, but no error code recieved"
70
+ warning err.chomp
71
+ end
72
+ else
73
+ error "Error running: `#{cmd.join(' ')}`", err.chomp
74
+ @status.fail!
75
+ end
76
+
77
+ return thr.success?
78
+ rescue => e
79
+ error e.class, e.message, e.backtrace.join("\n")
80
+ end
81
+ end
82
+
83
+ # Deletes passed in files
84
+ def delete(files)
85
+ # sync before we delete
86
+ sync
87
+ Array.wrap(files).each do |f|
88
+ info "removing #{f}"
89
+ FileUtils.rm(f)
90
+ error "#{f} wasn't removed" if File.exists?(f)
91
+ end
92
+ end
93
+
94
+ # Create a new directory
95
+ def mkdir(dir)
96
+ FileUtils.mkdir_p(File.expand_path(dir))
97
+ @status.fail! unless File.exists?(File.expand_path(dir))
98
+ end
99
+
100
+ # Copy files to destination
101
+ def copy(src = [], dest = nil)
102
+ destination = dest unless dest.nil?
103
+ source = src unless src.empty?
104
+
105
+ if source && destination
106
+ verified_copy(source, destination)
107
+ end
108
+ end
109
+
110
+ # Move files to destination
111
+ def move(src=[], dest = nil)
112
+ destination = dest unless dest.nil?
113
+ source = src unless src.empty?
114
+
115
+ if source && destination
116
+ verified_move(source, destination)
117
+ end
118
+ end
119
+
120
+ # Scp files to destination
121
+ # See: man scp
122
+ def scp(src, dest)
123
+ run "scp #{Array.wrap(src).join(' ')} #{dest}"
124
+ end
125
+ end
126
+ end
127
+ end
data/lib/conveyor.rb ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path('../lib', File.dirname(__FILE__))
3
+
4
+ require 'rubygems'
5
+ require 'active_support/core_ext'
6
+ require 'singleton'
7
+ require 'listen'
8
+ require 'yaml'
9
+ require 'rainbow'
10
+ require 'rb-readline'
11
+ require 'fileutils'
12
+ require 'eventmachine'
13
+ require 'em-websocket'
14
+ require "conveyor/version"
15
+
16
+ module Conveyor
17
+ autoload :Output, 'conveyor/output'
18
+ autoload :Foreman, 'conveyor/foreman'
19
+ autoload :Belt, 'conveyor/belt'
20
+ autoload :Worker, 'conveyor/worker'
21
+ autoload :Status, 'conveyor/status'
22
+ autoload :Input, 'conveyor/input'
23
+ autoload :Queue, 'conveyor/queue'
24
+ autoload :Websocket, 'conveyor/websocket'
25
+
26
+ def self.stop
27
+ Foreman.instance.stop!
28
+ EventMachine.stop
29
+ exit
30
+ end
31
+
32
+ def self.fm
33
+ Foreman.instance
34
+ end
35
+
36
+ def self.start
37
+ EventMachine.run do
38
+ trap("TERM") { stop }
39
+ trap("INT") { stop }
40
+
41
+ EventMachine.threadpool_size = fm.config[:threadpool] || 20
42
+
43
+ fm.info "Starting Conveyor v#{Conveyor::VERSION}"
44
+ fm.start
45
+ fm.info "Waiting for files", :color => :green
46
+ fm.info "Press CTRL-C to stop"
47
+ Conveyor::Websocket.start
48
+
49
+ EventMachine::PeriodicTimer.new(1) do
50
+ fm.output_status
51
+ end
52
+
53
+ EventMachine::PeriodicTimer.new(1) do
54
+ fm.check
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def watch(*args, &block)
61
+ fm.watch(*args, &block)
62
+ end
@@ -0,0 +1,15 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile ~/.gitignore_global
6
+
7
+ # Ignore bundler config
8
+ /.bundle
9
+
10
+ # Ignore the default SQLite database.
11
+ /db/*.sqlite3
12
+
13
+ # Ignore all logfiles and tempfiles.
14
+ /log/*.log
15
+ /tmp
data/webviewer/Gemfile ADDED
@@ -0,0 +1,39 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '3.2.3'
4
+
5
+ # Bundle edge Rails instead:
6
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
+
8
+ gem 'sqlite3'
9
+ gem 'haml'
10
+ gem 'bootstrap-sass', '~> 2.0.2'
11
+
12
+ # Gems used only for assets and not required
13
+ # in production environments by default.
14
+ group :assets do
15
+ gem 'sass-rails', '~> 3.2.3'
16
+ gem 'coffee-rails', '~> 3.2.1'
17
+
18
+ # See https://github.com/sstephenson/execjs#readme for more supported runtimes
19
+ gem 'therubyracer', :platform => :ruby
20
+
21
+ gem 'uglifier', '>= 1.0.3'
22
+ end
23
+
24
+ gem 'jquery-rails'
25
+
26
+ # To use ActiveModel has_secure_password
27
+ # gem 'bcrypt-ruby', '~> 3.0.0'
28
+
29
+ # To use Jbuilder templates for JSON
30
+ # gem 'jbuilder'
31
+
32
+ # Use unicorn as the app server
33
+ # gem 'unicorn'
34
+
35
+ # Deploy with Capistrano
36
+ # gem 'capistrano'
37
+
38
+ # To use debugger
39
+ # gem 'ruby-debug19', :require => 'ruby-debug'
@@ -0,0 +1,119 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ actionmailer (3.2.3)
5
+ actionpack (= 3.2.3)
6
+ mail (~> 2.4.4)
7
+ actionpack (3.2.3)
8
+ activemodel (= 3.2.3)
9
+ activesupport (= 3.2.3)
10
+ builder (~> 3.0.0)
11
+ erubis (~> 2.7.0)
12
+ journey (~> 1.0.1)
13
+ rack (~> 1.4.0)
14
+ rack-cache (~> 1.2)
15
+ rack-test (~> 0.6.1)
16
+ sprockets (~> 2.1.2)
17
+ activemodel (3.2.3)
18
+ activesupport (= 3.2.3)
19
+ builder (~> 3.0.0)
20
+ activerecord (3.2.3)
21
+ activemodel (= 3.2.3)
22
+ activesupport (= 3.2.3)
23
+ arel (~> 3.0.2)
24
+ tzinfo (~> 0.3.29)
25
+ activeresource (3.2.3)
26
+ activemodel (= 3.2.3)
27
+ activesupport (= 3.2.3)
28
+ activesupport (3.2.3)
29
+ i18n (~> 0.6)
30
+ multi_json (~> 1.0)
31
+ arel (3.0.2)
32
+ bootstrap-sass (2.0.2)
33
+ builder (3.0.0)
34
+ coffee-rails (3.2.2)
35
+ coffee-script (>= 2.2.0)
36
+ railties (~> 3.2.0)
37
+ coffee-script (2.2.0)
38
+ coffee-script-source
39
+ execjs
40
+ coffee-script-source (1.3.1)
41
+ erubis (2.7.0)
42
+ execjs (1.3.1)
43
+ multi_json (~> 1.0)
44
+ haml (3.1.4)
45
+ hike (1.2.1)
46
+ i18n (0.6.0)
47
+ journey (1.0.3)
48
+ jquery-rails (2.0.2)
49
+ railties (>= 3.2.0, < 5.0)
50
+ thor (~> 0.14)
51
+ json (1.7.0)
52
+ libv8 (3.3.10.4)
53
+ mail (2.4.4)
54
+ i18n (>= 0.4.0)
55
+ mime-types (~> 1.16)
56
+ treetop (~> 1.4.8)
57
+ mime-types (1.18)
58
+ multi_json (1.3.4)
59
+ polyglot (0.3.3)
60
+ rack (1.4.1)
61
+ rack-cache (1.2)
62
+ rack (>= 0.4)
63
+ rack-ssl (1.3.2)
64
+ rack
65
+ rack-test (0.6.1)
66
+ rack (>= 1.0)
67
+ rails (3.2.3)
68
+ actionmailer (= 3.2.3)
69
+ actionpack (= 3.2.3)
70
+ activerecord (= 3.2.3)
71
+ activeresource (= 3.2.3)
72
+ activesupport (= 3.2.3)
73
+ bundler (~> 1.0)
74
+ railties (= 3.2.3)
75
+ railties (3.2.3)
76
+ actionpack (= 3.2.3)
77
+ activesupport (= 3.2.3)
78
+ rack-ssl (~> 1.3.2)
79
+ rake (>= 0.8.7)
80
+ rdoc (~> 3.4)
81
+ thor (~> 0.14.6)
82
+ rake (0.9.2.2)
83
+ rdoc (3.12)
84
+ json (~> 1.4)
85
+ sass (3.1.16)
86
+ sass-rails (3.2.5)
87
+ railties (~> 3.2.0)
88
+ sass (>= 3.1.10)
89
+ tilt (~> 1.3)
90
+ sprockets (2.1.3)
91
+ hike (~> 1.2)
92
+ rack (~> 1.0)
93
+ tilt (~> 1.1, != 1.3.0)
94
+ sqlite3 (1.3.6)
95
+ therubyracer (0.10.1)
96
+ libv8 (~> 3.3.10)
97
+ thor (0.14.6)
98
+ tilt (1.3.3)
99
+ treetop (1.4.10)
100
+ polyglot
101
+ polyglot (>= 0.3.1)
102
+ tzinfo (0.3.33)
103
+ uglifier (1.2.4)
104
+ execjs (>= 0.3.0)
105
+ multi_json (>= 1.0.2)
106
+
107
+ PLATFORMS
108
+ ruby
109
+
110
+ DEPENDENCIES
111
+ bootstrap-sass (~> 2.0.2)
112
+ coffee-rails (~> 3.2.1)
113
+ haml
114
+ jquery-rails
115
+ rails (= 3.2.3)
116
+ sass-rails (~> 3.2.3)
117
+ sqlite3
118
+ therubyracer
119
+ uglifier (>= 1.0.3)