dj_dashboard 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +13 -0
  3. data/Gemfile.lock +115 -0
  4. data/README.rdoc +1 -1
  5. data/Rakefile +14 -22
  6. data/app/controllers/dj_dashboard/jobs_controller.rb +1 -0
  7. data/app/models/dj_dashboard/job.rb +15 -8
  8. data/app/views/layouts/dj_dashboard.html.haml +7 -0
  9. data/config/routes.rb +2 -4
  10. data/db/migrate/20111212074858_add_indexes_on_delayed_job.rb +15 -0
  11. data/dj_dashboard.gemspec +24 -0
  12. data/lib/dj_dashboard.rb +10 -4
  13. data/lib/dj_dashboard/engine.rb +10 -1
  14. data/lib/dj_dashboard/tasks/install.rb +59 -0
  15. data/lib/dj_dashboard/version.rb +1 -1
  16. data/lib/tasks/install.rake +8 -0
  17. data/public/javascripts/dj_dashboard/jobs.js +0 -0
  18. data/{app/assets → public}/stylesheets/dj_dashboard/jobs.css +0 -4
  19. data/test/dj_dashboard_test.rb +7 -0
  20. data/test/dummy/Rakefile +1 -1
  21. data/test/dummy/app/jobs/my_job.rb +1 -3
  22. data/test/dummy/app/views/layouts/application.html.erb +3 -3
  23. data/test/dummy/config/application.rb +8 -8
  24. data/test/dummy/config/database.yml +0 -3
  25. data/test/dummy/config/environment.rb +0 -4
  26. data/test/dummy/config/environments/development.rb +3 -7
  27. data/test/dummy/config/environments/production.rb +12 -23
  28. data/test/dummy/config/environments/test.rb +1 -5
  29. data/test/dummy/config/initializers/secret_token.rb +1 -1
  30. data/test/dummy/config/initializers/session_store.rb +1 -1
  31. data/test/dummy/config/locales/en.yml +1 -1
  32. data/test/dummy/config/routes.rb +56 -2
  33. data/test/dummy/db/migrate/{20111208045052_create_delayed_jobs.rb → 20111212042040_create_delayed_jobs.rb} +0 -0
  34. data/test/dummy/db/schema.rb +1 -1
  35. data/test/dummy/public/javascripts/application.js +2 -0
  36. data/test/dummy/public/javascripts/controls.js +965 -0
  37. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  38. data/test/dummy/public/javascripts/effects.js +1123 -0
  39. data/test/dummy/public/javascripts/prototype.js +6001 -0
  40. data/test/dummy/public/javascripts/rails.js +202 -0
  41. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  42. data/test/integration/navigation_test.rb +4 -7
  43. data/test/support/integration_case.rb +5 -0
  44. data/test/test_helper.rb +14 -2
  45. metadata +49 -115
  46. data/app/assets/javascripts/dj_dashboard/application.js +0 -9
  47. data/app/assets/javascripts/dj_dashboard/jobs.js +0 -2
  48. data/app/assets/stylesheets/dj_dashboard/application.css +0 -7
  49. data/app/controllers/dj_dashboard/application_controller.rb +0 -4
  50. data/app/helpers/dj_dashboard/application_helper.rb +0 -4
  51. data/app/helpers/dj_dashboard/jobs_helper.rb +0 -4
  52. data/app/views/dj_dashboard/jobs/index.html.erb.bak +0 -1
  53. data/app/views/layouts/dj_dashboard/application.html.erb +0 -14
  54. data/lib/tasks/dj_ashboard.rake +0 -4
  55. data/test/dj_dashbaord_test.rb +0 -7
  56. data/test/dummy/app/assets/javascripts/application.js +0 -9
  57. data/test/dummy/app/assets/stylesheets/application.css +0 -7
  58. data/test/dummy/app/jobs/failure_job.rb +0 -5
  59. data/test/dummy/app/jobs/my_other_job.rb +0 -9
  60. data/test/dummy/app/jobs/slow_job.rb +0 -8
  61. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  62. data/test/dummy/db/development.sqlite3 +0 -0
  63. data/test/dummy/log/development.log +0 -9289
  64. data/test/dummy/tmp/cache/assets/C6F/980/sprockets%2F501301344d0d02382d2e37e44e95d5b7 +0 -0
  65. data/test/dummy/tmp/cache/assets/C71/F20/sprockets%2Fb875931243c2e85243a73dbd34541b01 +0 -0
  66. data/test/dummy/tmp/cache/assets/C8B/FB0/sprockets%2Fa30656615c2357663ae857a489692eda +0 -0
  67. data/test/dummy/tmp/cache/assets/C9E/520/sprockets%2F489ce17948193acee58634965271c7b9 +0 -0
  68. data/test/dummy/tmp/cache/assets/CF0/810/sprockets%2F417d2188a30be6696a875a8fbc8f3584 +0 -0
  69. data/test/dummy/tmp/cache/assets/CF1/FA0/sprockets%2Fde520297c57ef5e7e01b98f685c31636 +0 -0
  70. data/test/dummy/tmp/cache/assets/CF3/0B0/sprockets%2F169489b2f9036266f8731f329bfee0cf +0 -0
  71. data/test/dummy/tmp/cache/assets/D16/930/sprockets%2Fa85c4d9513ce726ff104e78a676f113d +0 -0
  72. data/test/dummy/tmp/cache/assets/D18/5D0/sprockets%2Fff7d903fadac588f2531a0665964119d +0 -0
  73. data/test/dummy/tmp/cache/assets/D21/E00/sprockets%2F34aca167df809c799f08ff55d5718b14 +0 -0
  74. data/test/dummy/tmp/cache/assets/D24/070/sprockets%2F0bc96a7497e35f7b589b450a2e835ff7 +0 -0
  75. data/test/dummy/tmp/cache/assets/D6D/BD0/sprockets%2F0148f5b39b343ad81e5aee077c3cb86e +0 -0
  76. data/test/dummy/tmp/cache/assets/D70/530/sprockets%2Fcc672d70701efbd96a08d65e4d2890ac +0 -0
  77. data/test/dummy/tmp/cache/assets/D78/F00/sprockets%2Fc7ba90c63ddc30e47d829f0ff506298e +0 -0
  78. data/test/dummy/tmp/cache/assets/D87/010/sprockets%2Fdb3265fe875e06b1acf09985f95c39ff +0 -0
  79. data/test/dummy/tmp/cache/assets/DA3/1C0/sprockets%2Fff5b18546bbc1c8b66af624b38a168fe +0 -0
  80. data/test/dummy/tmp/cache/assets/DC0/560/sprockets%2Fef3cc623dc91b5acde21805230bb69ce +0 -0
  81. data/test/dummy/tmp/cache/assets/DD1/5D0/sprockets%2F2f8e642dbb496a52c8f0ab159b5faa9f +0 -0
  82. data/test/dummy/tmp/cache/assets/E0B/AF0/sprockets%2F763c1e8bd998b46bbe7bf3bab4968adb +0 -0
  83. data/test/dummy/tmp/cache/assets/E65/A80/sprockets%2Ff654007c2fcd9bd2b8fecd93f5fae3fb +0 -0
  84. data/test/functional/delayed_job_dashboard/jobs_controller_test.rb +0 -11
  85. data/test/unit/helpers/dj_dashboard/jobs_helper_test.rb +0 -6
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ test/dummy/db/*.sqlite3
5
+ test/dummy/log/*.log
6
+ test/dummy/tmp/
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rails", "3.0.11"
6
+ gem "capybara", ">= 0.4.0"
7
+ gem "sqlite3"
8
+ gem 'delayed_job'
9
+ gem 'haml'
10
+
11
+ # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
12
+ # gem 'ruby-debug'
13
+ # gem 'ruby-debug19'
data/Gemfile.lock ADDED
@@ -0,0 +1,115 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dj_dashboard (0.0.3)
5
+ haml
6
+ sass
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ abstract (1.0.0)
12
+ actionmailer (3.0.11)
13
+ actionpack (= 3.0.11)
14
+ mail (~> 2.2.19)
15
+ actionpack (3.0.11)
16
+ activemodel (= 3.0.11)
17
+ activesupport (= 3.0.11)
18
+ builder (~> 2.1.2)
19
+ erubis (~> 2.6.6)
20
+ i18n (~> 0.5.0)
21
+ rack (~> 1.2.1)
22
+ rack-mount (~> 0.6.14)
23
+ rack-test (~> 0.5.7)
24
+ tzinfo (~> 0.3.23)
25
+ activemodel (3.0.11)
26
+ activesupport (= 3.0.11)
27
+ builder (~> 2.1.2)
28
+ i18n (~> 0.5.0)
29
+ activerecord (3.0.11)
30
+ activemodel (= 3.0.11)
31
+ activesupport (= 3.0.11)
32
+ arel (~> 2.0.10)
33
+ tzinfo (~> 0.3.23)
34
+ activeresource (3.0.11)
35
+ activemodel (= 3.0.11)
36
+ activesupport (= 3.0.11)
37
+ activesupport (3.0.11)
38
+ arel (2.0.10)
39
+ builder (2.1.2)
40
+ capybara (1.1.2)
41
+ mime-types (>= 1.16)
42
+ nokogiri (>= 1.3.3)
43
+ rack (>= 1.0.0)
44
+ rack-test (>= 0.5.4)
45
+ selenium-webdriver (~> 2.0)
46
+ xpath (~> 0.1.4)
47
+ childprocess (0.2.3)
48
+ ffi (~> 1.0.6)
49
+ daemons (1.1.4)
50
+ delayed_job (2.1.4)
51
+ activesupport (~> 3.0)
52
+ daemons
53
+ erubis (2.6.6)
54
+ abstract (>= 1.0.0)
55
+ ffi (1.0.11)
56
+ haml (3.1.4)
57
+ i18n (0.5.0)
58
+ json (1.6.3)
59
+ mail (2.2.19)
60
+ activesupport (>= 2.3.6)
61
+ i18n (>= 0.4.0)
62
+ mime-types (~> 1.16)
63
+ treetop (~> 1.4.8)
64
+ mime-types (1.17.2)
65
+ multi_json (1.0.4)
66
+ nokogiri (1.5.0)
67
+ polyglot (0.3.3)
68
+ rack (1.2.4)
69
+ rack-mount (0.6.14)
70
+ rack (>= 1.0.0)
71
+ rack-test (0.5.7)
72
+ rack (>= 1.0)
73
+ rails (3.0.11)
74
+ actionmailer (= 3.0.11)
75
+ actionpack (= 3.0.11)
76
+ activerecord (= 3.0.11)
77
+ activeresource (= 3.0.11)
78
+ activesupport (= 3.0.11)
79
+ bundler (~> 1.0)
80
+ railties (= 3.0.11)
81
+ railties (3.0.11)
82
+ actionpack (= 3.0.11)
83
+ activesupport (= 3.0.11)
84
+ rake (>= 0.8.7)
85
+ rdoc (~> 3.4)
86
+ thor (~> 0.14.4)
87
+ rake (0.9.2.2)
88
+ rdoc (3.11)
89
+ json (~> 1.4)
90
+ rubyzip (0.9.5)
91
+ sass (3.1.11)
92
+ selenium-webdriver (2.15.0)
93
+ childprocess (>= 0.2.1)
94
+ ffi (~> 1.0.9)
95
+ multi_json (~> 1.0.4)
96
+ rubyzip
97
+ sqlite3 (1.3.5)
98
+ thor (0.14.6)
99
+ treetop (1.4.10)
100
+ polyglot
101
+ polyglot (>= 0.3.1)
102
+ tzinfo (0.3.31)
103
+ xpath (0.1.4)
104
+ nokogiri (~> 1.3)
105
+
106
+ PLATFORMS
107
+ ruby
108
+
109
+ DEPENDENCIES
110
+ capybara (>= 0.4.0)
111
+ delayed_job
112
+ dj_dashboard!
113
+ haml
114
+ rails (= 3.0.11)
115
+ sqlite3
data/README.rdoc CHANGED
@@ -1,3 +1,3 @@
1
1
  = DjDashboard
2
2
 
3
- This project rocks and uses MIT-LICENSE.
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile CHANGED
@@ -1,30 +1,13 @@
1
- #!/usr/bin/env rake
1
+ # encoding: UTF-8
2
+ require 'rubygems'
2
3
  begin
3
4
  require 'bundler/setup'
4
5
  rescue LoadError
5
6
  puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
7
  end
7
- begin
8
- require 'rdoc/task'
9
- rescue LoadError
10
- require 'rdoc/rdoc'
11
- require 'rake/rdoctask'
12
- RDoc::Task = Rake::RDocTask
13
- end
14
8
 
15
- RDoc::Task.new(:rdoc) do |rdoc|
16
- rdoc.rdoc_dir = 'rdoc'
17
- rdoc.title = 'DjDashboard'
18
- rdoc.options << '--line-numbers'
19
- rdoc.rdoc_files.include('README.rdoc')
20
- rdoc.rdoc_files.include('lib/**/*.rb')
21
- end
22
-
23
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
- load 'rails/tasks/engine.rake'
25
-
26
-
27
- Bundler::GemHelper.install_tasks
9
+ require 'rake'
10
+ require 'rake/rdoctask'
28
11
 
29
12
  require 'rake/testtask'
30
13
 
@@ -35,5 +18,14 @@ Rake::TestTask.new(:test) do |t|
35
18
  t.verbose = false
36
19
  end
37
20
 
38
-
39
21
  task :default => :test
22
+
23
+ Rake::RDocTask.new(:rdoc) do |rdoc|
24
+ rdoc.rdoc_dir = 'rdoc'
25
+ rdoc.title = 'DjDashboard'
26
+ rdoc.options << '--line-numbers' << '--inline-source'
27
+ rdoc.rdoc_files.include('README.rdoc')
28
+ rdoc.rdoc_files.include('lib/**/*.rb')
29
+ end
30
+
31
+ Bundler::GemHelper.install_tasks
@@ -1,5 +1,6 @@
1
1
  module DjDashboard
2
2
  class JobsController < ApplicationController
3
+ layout 'dj_dashboard'
3
4
 
4
5
  def index
5
6
  @jobs = Job.fetch
@@ -1,15 +1,22 @@
1
+ require 'set'
2
+
1
3
  module DjDashboard
2
4
  class Job
3
5
  def self.fetch(opts={})
4
- jobs = Delayed::Job.select(:handler).group(:handler).map { |job| { handler: job[:handler].chomp, name: job[:handler].scan(/object:(\w+)\ /).flatten.first } }
5
- jobs.each do |job|
6
- job[:running] = Delayed::Job.where("handler like '%#{job[:name]}%'").where("locked_at is not null").count
7
- job[:failed] = Delayed::Job.where("handler like '%#{job[:name]}%'").where("failed_at is not null and attempts > 3").count
8
- job[:pending] = Delayed::Job.where("handler like '%#{job[:name]}%'").where(locked_at: nil, failed_at: nil).count
9
- job[:retrying] = Delayed::Job.where("handler like '%#{job[:name]}%'").where(locked_at: nil).where("failed_at is not null").count
6
+ results = Delayed::Job.select(:handler).group(:handler)
7
+ names = results.reduce(Set.new) do |names, result|
8
+ names << result[:handler].chomp.scan(/ruby\/\w+:([a-zA-Z:]+)\ /).flatten.first
9
+ end
10
+
11
+ names.map do |job|
12
+ {
13
+ name: job,
14
+ running: Delayed::Job.where("handler like '%#{job}%'").where("locked_at is not null").count,
15
+ failed: Delayed::Job.where("handler like '%#{job}%'").where("failed_at is not null and attempts > 3").count,
16
+ pending: Delayed::Job.where("handler like '%#{job}%'").where(locked_at: nil, failed_at: nil).count,
17
+ retrying: Delayed::Job.where("handler like '%#{job}%'").where(locked_at: nil).where("failed_at is not null").count
18
+ }
10
19
  end
11
-
12
- jobs
13
20
  end
14
21
  end
15
22
  end
@@ -0,0 +1,7 @@
1
+ !!! 5
2
+ %head
3
+ %title Delayed Job Dashboard
4
+ = stylesheet_link_tag('dj_dashboard/jobs.css')
5
+ = javascript_include_tag('dj_dashboard/jobs.js')
6
+ %body
7
+ =yield
data/config/routes.rb CHANGED
@@ -1,5 +1,3 @@
1
- DjDashboard::Engine.routes.draw do
2
- #get "jobs/index"
3
-
4
- root :to => "jobs#index"
1
+ Rails.application.routes.draw do
2
+ get "dj_dashboard" => "dj_dashboard/jobs#index", :as => :dj_dashboard
5
3
  end
@@ -0,0 +1,15 @@
1
+ class AddIndexesOnDelayedJob < ActiveRecord::Migration
2
+ def self.up
3
+ add_index :delayed_jobs, :locked_at
4
+ add_index :delayed_jobs, :failed_at
5
+ add_index :delayed_jobs, [:locked_at, :failed_at]
6
+ add_index :delayed_jobs, [:failed_at, :attempts]
7
+ end
8
+
9
+ def self.down
10
+ remove_index :delayed_jobs, :locked_at
11
+ remove_index :delayed_jobs, :failed_at
12
+ remove_index :delayed_jobs, [:locked_at, :failed_at]
13
+ remove_index :delayed_jobs, [:failed_at, :attempts]
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path("../lib/dj_dashboard/version", __FILE__)
2
+
3
+ # Provide a simple gemspec so you can easily use your enginex
4
+ # project in your rails apps through git.
5
+ Gem::Specification.new do |s|
6
+ s.name = "dj_dashboard"
7
+ s.version = DjDashboard::VERSION
8
+ s.authors = ["Ben Kempner"]
9
+ s.email = ["ben.kempner@gmail.com"]
10
+ s.homepage = "http://www.github.com/bkempner/dj_dashboard"
11
+ s.summary = "Delayed Job Dashboard"
12
+ s.description = "Delayed Job Dashboard"
13
+ s.files = Dir["{app,lib,config}/**/*"] + ["MIT-LICENSE", "Rakefile", "Gemfile", "README.rdoc"]
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency "haml"
21
+ s.add_dependency "sass"
22
+
23
+ s.add_development_dependency "sqlite3"
24
+ end
data/lib/dj_dashboard.rb CHANGED
@@ -1,7 +1,13 @@
1
- require "dj_dashboard/engine"
2
- require 'delayed_job'
3
- require 'haml'
4
- require 'sass'
1
+ require 'active_support/dependencies'
5
2
 
6
3
  module DjDashboard
4
+
5
+ mattr_accessor :app_root
6
+
7
+ def self.setup
8
+ yield self
9
+ end
10
+
7
11
  end
12
+
13
+ require 'dj_dashboard/engine'
@@ -1,5 +1,14 @@
1
1
  module DjDashboard
2
2
  class Engine < Rails::Engine
3
- isolate_namespace DjDashboard
3
+ initializer 'dj_dashboard.load_app_instance_data' do |app|
4
+ DjDashboard.setup do |config|
5
+ config.app_root = app.root
6
+ end
7
+ end
8
+
9
+ initializer 'dj_dashboard.load_static_assets' do |app|
10
+ app.middleware.use ::ActionDispatch::Static, "#{root}/public" if Rails.version =~ /3.0/
11
+ app.middleware.use ::ActionDispatch::Static, "#{root}/app/assets" if Rails.version =~ /3.1/
12
+ end
4
13
  end
5
14
  end
@@ -0,0 +1,59 @@
1
+ require 'rails/generators'
2
+
3
+ module DjDashboard
4
+ module Tasks
5
+ class Install
6
+ def self.run
7
+ puts 'installing dj_dashboard'
8
+ copy_assets_files
9
+ copy_migration_files
10
+ end
11
+
12
+ def self.copy_assets_files
13
+ return nil if Rails.version =~ /3.0/ # not needed for rails 3.0
14
+ origin = File.join(gem_path, 'public')
15
+ destination = Rails.root.join('app/assets') if Rails.version =~ /3.1/
16
+ destination = Rails.root.join('public') if Rails.version =~ /3.0/
17
+ puts copy_files(%w( stylesheets images javascripts ), origin, destination, 'dj_dashboard')
18
+ end
19
+
20
+ def self.copy_migration_files
21
+ puts 'now copying migration files'
22
+ origin = File.join(gem_path, 'db')
23
+ destination = Rails.root.join('db')
24
+ puts copy_files(%w( migrate ), origin, destination)
25
+ end
26
+
27
+ def self.gem_path
28
+ File.expand_path('../../..', File.dirname(__FILE__))
29
+ end
30
+
31
+ def self.copy_files(directories, origin, destination, prefix = nil)
32
+ directories.each do |directory|
33
+ dirs = [origin, directory, prefix, '**/*'].compact
34
+ Dir[File.join(*dirs)].each do |file|
35
+ relative = file.gsub(/^#{origin}\//, '')
36
+ dirs = [destination, relative].compact
37
+ dest_file = File.join(*dirs)
38
+ dest_dir = File.dirname(dest_file)
39
+
40
+ if !File.exist?(dest_dir)
41
+ FileUtils.mkdir_p(dest_dir)
42
+ end
43
+
44
+ copier.copy_file(file, dest_file) unless File.directory?(file)
45
+ end
46
+ end
47
+ end
48
+
49
+ def self.copier
50
+ unless @copier
51
+ Rails::Generators::Base.source_root(gem_path)
52
+ @copier = Rails::Generators::Base.new
53
+ end
54
+ @copier
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -1,3 +1,3 @@
1
1
  module DjDashboard
2
- VERSION = "0.0.2"
2
+ VERSION = '0.0.3'
3
3
  end
@@ -0,0 +1,8 @@
1
+ require File.expand_path('../../dj_dashboard/tasks/install', __FILE__)
2
+
3
+ namespace :dj_dashboard do
4
+ desc "Install dj_dashboard"
5
+ task :install do
6
+ DjDashboard::Tasks::Install.run
7
+ end
8
+ end
File without changes
@@ -1,7 +1,3 @@
1
- /*
2
- Place all the styles related to the matching controller here.
3
- They will automatically be included in application.css.
4
- */
5
1
  body { font-family: Arial; color: #fff; background-color: #333 }
6
2
  .title { width: 750px; margin: 25px auto; margin-top: 50px; padding-left: 15px; font-size: 36px; border-radius: 15px; background-color: #444; padding: 20px; }
7
3
  #jobs { border-collapse: collapse; border: 1px solid #333; margin: 0 auto; -moz-border-radius: 15px; width: 750px; }
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class DjDashboardTest < ActiveSupport::TestCase
4
+ test "truth" do
5
+ assert_kind_of Module, DjDashboard
6
+ end
7
+ end
data/test/dummy/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
- #!/usr/bin/env rake
2
1
  # Add your own tasks in files placed in lib/tasks ending in .rake,
3
2
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
3
 
5
4
  require File.expand_path('../config/application', __FILE__)
5
+ require 'rake'
6
6
 
7
7
  Dummy::Application.load_tasks
@@ -1,9 +1,7 @@
1
1
  class MyJob
2
2
 
3
3
  def perform
4
- sleep(3)
5
- puts 'hi'
6
- sleep(300)
4
+ sleep(60)
7
5
  end
8
6
 
9
7
  end