orats 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/Gemfile +1 -1
  4. data/{LICENSE.txt → LICENSE} +21 -21
  5. data/README.md +51 -346
  6. data/Rakefile +1 -1
  7. data/bin/orats +5 -2
  8. data/lib/orats/argv_adjust.rb +61 -0
  9. data/lib/orats/cli.rb +53 -141
  10. data/lib/orats/cli_help/new +27 -0
  11. data/lib/orats/cli_help/nuke +19 -0
  12. data/lib/orats/commands/new/exec.rb +59 -0
  13. data/lib/orats/commands/new/rails.rb +197 -0
  14. data/lib/orats/commands/new/server.rb +67 -0
  15. data/lib/orats/commands/nuke.rb +66 -44
  16. data/lib/orats/common.rb +76 -0
  17. data/lib/orats/postgres.rb +90 -0
  18. data/lib/orats/process.rb +35 -0
  19. data/lib/orats/redis.rb +25 -0
  20. data/lib/orats/shell.rb +12 -0
  21. data/lib/orats/templates/auth.rb +96 -82
  22. data/lib/orats/templates/base.rb +115 -110
  23. data/lib/orats/templates/includes/new/rails/.env +28 -28
  24. data/lib/orats/templates/includes/new/rails/Gemfile +4 -4
  25. data/lib/orats/templates/includes/new/rails/config/{whenever.rb → schedule.rb} +0 -0
  26. data/lib/orats/ui.rb +33 -0
  27. data/lib/orats/version.rb +3 -2
  28. data/lib/orats.rb +2 -1
  29. data/orats.gemspec +7 -5
  30. data/test/integration/cli_test.rb +28 -177
  31. data/test/test_helper.rb +24 -9
  32. metadata +17 -29
  33. data/lib/orats/commands/common.rb +0 -146
  34. data/lib/orats/commands/diff/compare.rb +0 -106
  35. data/lib/orats/commands/diff/exec.rb +0 -60
  36. data/lib/orats/commands/diff/parse.rb +0 -66
  37. data/lib/orats/commands/inventory.rb +0 -100
  38. data/lib/orats/commands/playbook.rb +0 -60
  39. data/lib/orats/commands/project/exec.rb +0 -74
  40. data/lib/orats/commands/project/rails.rb +0 -162
  41. data/lib/orats/commands/project/server.rb +0 -57
  42. data/lib/orats/commands/role.rb +0 -70
  43. data/lib/orats/commands/ui.rb +0 -47
  44. data/lib/orats/templates/includes/inventory/group_vars/all.yml +0 -202
  45. data/lib/orats/templates/includes/inventory/hosts +0 -8
  46. data/lib/orats/templates/includes/playbook/Galaxyfile +0 -15
  47. data/lib/orats/templates/includes/playbook/common.yml +0 -23
  48. data/lib/orats/templates/includes/playbook/site.yml +0 -36
  49. data/lib/orats/templates/includes/role/.travis.yml +0 -19
  50. data/lib/orats/templates/includes/role/README.md +0 -62
  51. data/lib/orats/templates/includes/role/meta/main.yml +0 -123
  52. data/lib/orats/templates/includes/role/tests/inventory +0 -1
  53. data/lib/orats/templates/includes/role/tests/main.yml +0 -7
  54. data/lib/orats/templates/playbook.rb +0 -119
  55. data/lib/orats/templates/role.rb +0 -144
@@ -1,60 +0,0 @@
1
- require 'orats/commands/common'
2
- require 'orats/commands/diff/parse'
3
- require 'orats/commands/diff/compare'
4
- require 'orats/version'
5
-
6
- module Orats
7
- module Commands
8
- module Diff
9
- class Exec < Commands::Common
10
- include Parse
11
- include Compare
12
-
13
- attr_accessor :diff_list
14
-
15
- def initialize(target_path = '', options = {})
16
- super
17
-
18
- @remote_galaxyfile = galaxyfile url_to_string(@remote_paths[:galaxyfile])
19
- @remote_playbook = playbook url_to_string(@remote_paths[:playbook])
20
- @remote_hosts = hosts url_to_string(@remote_paths[:hosts])
21
- @remote_inventory = inventory url_to_string(@remote_paths[:inventory])
22
-
23
- galaxyfile_path = @options[:galaxyfile]
24
- playbook_path = @options[:playbook]
25
- hosts_path = @options[:hosts]
26
- inventory_path = @options[:inventory]
27
-
28
- if !@options[:inventory].empty? && File.directory?(@options[:inventory])
29
- hosts_path = File.join(inventory_path, 'hosts')
30
- inventory_path = File.join(inventory_path, 'group_vars/all.yml')
31
- end
32
-
33
- if !@options[:playbook].empty? && File.directory?(@options[:playbook])
34
- galaxyfile_path = File.join(playbook_path, 'Galaxyfile')
35
- playbook_path = File.join(playbook_path, 'site.yml')
36
- end
37
-
38
- @your_galaxyfile = galaxyfile file_to_string (galaxyfile_path) unless galaxyfile_path.empty?
39
- @your_playbook = playbook file_to_string(playbook_path) unless playbook_path.empty?
40
- @your_hosts = hosts file_to_string(hosts_path) unless hosts_path.empty?
41
- @your_inventory = inventory file_to_string(inventory_path) unless inventory_path.empty?
42
-
43
- end
44
-
45
- def init
46
- remote_gem_vs_yours
47
-
48
- remote_vs_yours('galaxyfile', @remote_galaxyfile,
49
- @your_galaxyfile, false) unless @your_galaxyfile.nil?
50
- remote_vs_yours('playbook', @remote_playbook,
51
- @your_playbook, true) unless @your_playbook.nil?
52
- remote_vs_yours('hosts', @remote_hosts,
53
- @your_hosts, true) unless @your_hosts.nil?
54
- remote_vs_yours('inventory', @remote_inventory,
55
- @your_inventory, true) unless @your_inventory.nil?
56
- end
57
- end
58
- end
59
- end
60
- end
@@ -1,66 +0,0 @@
1
- module Orats
2
- module Commands
3
- module Diff
4
- module Parse
5
- def gem_version
6
- "v#{url_to_string(@remote_paths[:version]).match(/'(.*)'/)[1..-1].first}"
7
- end
8
-
9
- def galaxyfile(contents)
10
- contents.split
11
- end
12
-
13
- def hosts(contents)
14
- contents.scan(/^\[.*\]/)
15
- end
16
-
17
- def inventory(contents)
18
- # pluck out all of the values contained with {{ }}
19
- ansible_variables = contents.scan(/\{\{([^{{}}]*)\}\}/)
20
-
21
- # remove the leading space
22
- ansible_variables.map! { |line| line.first[0] = '' }
23
-
24
- # match every line that is not a comment and contains a colon
25
- inventory_variables = contents.scan(/^[^#].*:/)
26
-
27
- inventory_variables.map! do |line|
28
- # only strip lines that need it
29
- line.strip! if line.include?(' ') || line.include?("\n")
30
-
31
- # get rid of the trailing colon
32
- line.chomp(':')
33
-
34
- # if a value of a certain variable has a colon then the regex
35
- # picks this up as a match. only take the variable name
36
- # if this happens to occur
37
- line.split(':').first if line.include?(':')
38
- end
39
-
40
- (ansible_variables + inventory_variables).uniq.delete_if(&:empty?)
41
- end
42
-
43
- def playbook(contents)
44
- roles = contents.scan(/^.*role:.*/)
45
-
46
- roles.map! do |line|
47
- line.strip! if line.include?(' ') || line.include?("\n")
48
-
49
- role_parts = line.split('role:')
50
-
51
- # start at the actual role name
52
- line = role_parts[1]
53
-
54
- if line.include?(',')
55
- line = line.split(',').first
56
- end
57
-
58
- line.strip! if line.include?(' ')
59
- end
60
-
61
- roles.uniq
62
- end
63
- end
64
- end
65
- end
66
- end
@@ -1,100 +0,0 @@
1
- require 'securerandom'
2
- require 'orats/commands/common'
3
- require 'orats/commands/project/rails'
4
-
5
- module Orats
6
- module Commands
7
- class Inventory < Common
8
- include Project::Rails
9
-
10
- def initialize(target_path = '', options = {})
11
- super
12
- end
13
-
14
- def init
15
- exit_if_path_exists('inventory')
16
-
17
- create_inventory
18
-
19
- secrets_path = "#{@target_path}/secrets"
20
- create_secrets secrets_path
21
-
22
- log_task 'Update secrets path in group_vars/all.yml'
23
- gsub_file "#{@target_path}/#{fix_path_for_user(Common::RELATIVE_PATHS[:inventory])}",
24
- '/home/yourname/dev/testproj/secrets', File.expand_path(secrets_path)
25
-
26
- log_task 'Update place holder app name in group_vars/all.yml'
27
- gsub_file "#{@target_path}/#{fix_path_for_user(Common::RELATIVE_PATHS[:inventory])}",
28
- 'testproj', File.basename(@target_path)
29
-
30
- log_task 'Add ssh keypair'
31
- run "ssh-keygen -t rsa -P '' -f #{secrets_path}/id_rsa"
32
-
33
- log_task 'Add self signed ssl certificates'
34
- run create_rsa_certificate(secrets_path, 'sslkey.key', 'sslcert.crt')
35
-
36
- log_task 'Add monit pem file'
37
- run "#{create_rsa_certificate(secrets_path,
38
- 'monit.pem', 'monit.pem')} && openssl gendh 512 >> #{secrets_path}/monit.pem"
39
-
40
- log_success
41
- end
42
-
43
- private
44
-
45
- def create_inventory
46
- log_task 'Add ansible inventory'
47
- run "mkdir -p #{@target_path}/inventory/group_vars"
48
-
49
- local_to_user Common::RELATIVE_PATHS[:hosts]
50
- local_to_user Common::RELATIVE_PATHS[:inventory]
51
- end
52
-
53
- def local_to_user(file)
54
- fixed_file = fix_path_for_user(file)
55
-
56
- log_task "Add #{fixed_file}"
57
- run "cp #{base_path}/#{file} #{@target_path}/#{fixed_file}"
58
- end
59
-
60
- def create_secrets(secrets_path)
61
- log_task 'Add ansible secrets'
62
- run "mkdir #{secrets_path}"
63
-
64
- save_secret_string "#{secrets_path}/postgres_password"
65
- save_secret_string "#{secrets_path}/redis_password"
66
- save_secret_string "#{secrets_path}/mail_password"
67
- save_secret_string "#{secrets_path}/rails_token"
68
- save_secret_string "#{secrets_path}/devise_token"
69
- save_secret_string "#{secrets_path}/devise_pepper_token"
70
- end
71
-
72
- def save_secret_string(file)
73
- File.open(file, 'w+') { |f| f.write(SecureRandom.hex(64)) }
74
- end
75
-
76
- def create_rsa_certificate(secrets_path, keyout, out)
77
- "openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -subj '/C=US/ST=Foo/L=Bar/O=Baz/CN=qux.com' -keyout #{secrets_path}/#{keyout} -out #{secrets_path}/#{out}"
78
- end
79
-
80
- def log_success
81
- log_status_top 'success', 'Everything has been setup successfully',
82
- :cyan
83
- puts
84
- log_status_bottom 'question', 'Not sure what to do?', :yellow, true
85
- log_status_bottom 'answer', 'Check out the inventory/hosts file',
86
- :white, true
87
- log_status_bottom 'answer', 'Check out the inventory/group_vars/all.yml file', :white
88
-
89
- log_status_bottom 'question', 'Are you new to ansible?', :yellow, true
90
- log_status_bottom 'answer',
91
- 'http://docs.ansible.com/intro_getting_started.html',
92
- :white
93
- end
94
-
95
- def fix_path_for_user(file)
96
- file.sub('templates/includes', '')
97
- end
98
- end
99
- end
100
- end
@@ -1,60 +0,0 @@
1
- require 'orats/commands/common'
2
- require 'orats/commands/project/rails'
3
-
4
- module Orats
5
- module Commands
6
- class Playbook < Common
7
- include Project::Rails
8
-
9
- def initialize(target_path = '', options = {})
10
- super
11
- end
12
-
13
- def init
14
- exit_if_updating_playbook
15
-
16
- rails_template 'playbook'
17
- custom_rails_template unless @options[:custom].empty?
18
-
19
- galaxy_install
20
- log_success
21
- end
22
-
23
- private
24
-
25
- def exit_if_updating_playbook
26
- galaxyfile = File.join(@target_path, 'Galaxyfile')
27
-
28
- if File.exist?(galaxyfile)
29
- galaxy_install 'Update'
30
- exit 1
31
- end
32
- end
33
-
34
- def galaxy_install(git_commit_type='Add')
35
- log_task "#{git_commit_type} ansible roles from the galaxy"
36
-
37
- galaxy_install = "ansible-galaxy install -r #{@target_path}/Galaxyfile --roles-path #{@target_path}/roles --force"
38
-
39
- run galaxy_install
40
-
41
- git_commit "#{git_commit_type} galaxy installed roles"
42
- end
43
-
44
- def log_success
45
- log_status_top 'success', 'Everything has been setup successfully',
46
- :cyan
47
- puts
48
- log_status_bottom 'question', 'Are most of your apps similar?', :yellow, true
49
- log_status_bottom 'answer', 'You only need to generate one playbook and you just did',
50
- :white, true
51
- log_status_bottom 'answer', 'Use the inventory in each project to customize certain things', :white
52
-
53
- log_status_bottom 'question', 'Are you new to ansible?', :yellow, true
54
- log_status_bottom 'answer',
55
- 'http://docs.ansible.com/intro_getting_started.html',
56
- :white
57
- end
58
- end
59
- end
60
- end
@@ -1,74 +0,0 @@
1
- require 'orats/commands/common'
2
- require 'orats/commands/inventory'
3
- require 'orats/commands/project/rails'
4
- require 'orats/commands/project/server'
5
-
6
- module Orats
7
- module Commands
8
- module Project
9
- class Exec < Commands::Common
10
- include Rails
11
- include Server
12
-
13
- PROJECT_TEMPLATES = {
14
- auth: 'add authentication and authorization'
15
- }
16
-
17
- def initialize(target_path = '', options = {})
18
- super
19
-
20
- @active_path = services_path
21
- end
22
-
23
- def list_templates
24
- log_status_top 'templates', 'Available templates to choose from:',
25
- :blue
26
- puts
27
- PROJECT_TEMPLATES.each_pair do |key, value|
28
- log_status_bottom key, value, :cyan, true
29
- log_status_bottom 'usage', "orats project /tmp/foo --template #{key}",
30
- :white
31
- end
32
- end
33
-
34
- def init
35
- check_exit_conditions
36
-
37
- rails_template 'base' do
38
- gsub_postgres_info
39
- gsub_redis_info unless @options[:redis_password].empty?
40
- gsub_project_path
41
- gsub_readme
42
-
43
- bundle_install
44
- bundle_binstubs
45
- spring_binstub
46
-
47
- create_and_migrate_database
48
- generate_home_page
49
- generate_favicons
50
- end
51
-
52
- if template_exist?(@options[:template])
53
- rails_template @options[:template], '--skip ' do
54
- migrate_and_seed_database
55
- end
56
- end
57
-
58
- Commands::Inventory.new(@target_path,
59
- @options).init unless @options[:skip_ansible]
60
-
61
- custom_rails_template unless @options[:custom].empty?
62
-
63
- server_start
64
- end
65
-
66
- private
67
-
68
- def services_path
69
- "#{@target_path}/services/#{File.basename @target_path}"
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,162 +0,0 @@
1
- module Orats
2
- module Commands
3
- module Project
4
- module Rails
5
- def check_exit_conditions(check_running_processes: true)
6
- exit_if_process :not_found, 'rails', 'git'
7
- exit_if_process :not_running, 'postgres', 'redis' if check_running_processes
8
- exit_if_path_exists
9
- exit_if_invalid_template
10
- end
11
-
12
- def rails_template(command, flags = '')
13
- orats_template = "--template #{base_path}/templates/#{command}.rb"
14
-
15
- run "rails new #{@active_path} #{flags} --skip-bundle #{orats_template unless command.empty?}"
16
- yield if block_given?
17
- end
18
-
19
- def custom_rails_template
20
- log_task 'Run custom rails template'
21
-
22
- @options[:custom].include?('://') ? url_to_string(@options[:custom])
23
- : file_to_string(@options[:custom])
24
-
25
- rails_template '', "--skip --template #{@options[:custom]}"
26
- end
27
-
28
- def gsub_postgres_info
29
- log_task 'Update the postgres connection details'
30
- gsub_file "#{@active_path}/.env", 'DATABASE_HOST: localhost', "DATABASE_HOST: #{@options[:pg_location]}"
31
- gsub_file "#{@active_path}/.env", ': postgres', ": #{@options[:pg_username]}"
32
- gsub_file "#{@active_path}/.env", ': supersecrets', ": #{@options[:pg_password]}"
33
-
34
- git_commit 'Update the postgres connection details'
35
- end
36
-
37
- def gsub_redis_info
38
- log_task 'Update the redis connection details'
39
- gsub_file "#{@active_path}/.env", 'HE_PASSWORD: ""', "HE_PASSWORD: #{@options[:redis_password]}"
40
- gsub_file "#{@active_path}/.env", 'CACHE_HOST: localhost', "CACHE_HOST: #{@options[:redis_location]}"
41
-
42
- git_commit 'Update the redis connection details'
43
- end
44
-
45
- def gsub_project_path
46
- log_task 'Update the project path'
47
- gsub_file "#{@active_path}/.env", ': /home/yourname/dev/testproj',
48
- ": #{File.expand_path(@active_path)}"
49
-
50
- git_commit 'Update the project path'
51
- end
52
-
53
- def gsub_readme
54
- log_task 'Update the readme'
55
- gsub_file "#{@active_path}/README.md", 'VERSION', VERSION
56
-
57
- git_commit 'Update the version'
58
- end
59
-
60
- def bundle_install
61
- log_task 'Run bundle install, this may take a while'
62
- run_from @active_path, 'bundle install'
63
-
64
- git_commit 'Add Gemfile.lock'
65
- end
66
-
67
- def bundle_binstubs
68
- log_task 'Run bundle binstubs for a few gems'
69
- run_from @active_path, 'bundle binstubs whenever puma sidekiq backup'
70
-
71
- git_commit 'Add binstubs for the important gems'
72
- end
73
-
74
- def spring_binstub
75
- log_task 'Run spring binstub'
76
- run_from @active_path, 'bundle exec spring binstub --all'
77
-
78
- git_commit 'Add spring binstubs for all of the bins'
79
- end
80
-
81
- def run_rake(command)
82
- log_task 'Run rake command'
83
-
84
- run_from @active_path, "bundle exec rake #{command}"
85
- end
86
-
87
- def generate_home_page
88
- kill_spring_servers
89
-
90
- log_task 'Add pages controller with static page'
91
- run_from @active_path, 'bundle exec rails g controller Pages home'
92
-
93
- gsub_file "#{@active_path}/config/routes.rb", " # root 'welcome#index'" do
94
- <<-S
95
- root 'pages#home'
96
- S
97
- end
98
- gsub_file "#{@active_path}/config/routes.rb", " get 'pages/home'\n\n", ''
99
-
100
- gsub_file "#{@active_path}/test/controllers/pages_controller_test.rb",
101
- '"should get home"', "'expect home page'"
102
-
103
- run_from @active_path, "rm app/views/pages/home.html.erb"
104
- Commands::Common.copy_from_local_gem 'new/rails/app/views/pages/home.html.erb',
105
- "#{@active_path}/app/views/pages/home.html.erb"
106
- gsub_file "#{@active_path}/app/views/pages/home.html.erb",
107
- 'vVERSION', VERSION
108
-
109
- git_commit 'Add pages controller with home page'
110
- end
111
-
112
- def generate_favicons
113
- log_task 'Add favicons'
114
- run_rake 'orats:favicons'
115
- git_commit 'Add favicons'
116
- end
117
-
118
- def create_and_migrate_database
119
- run_rake 'db:create:all db:migrate'
120
- git_commit 'Add the database schema file'
121
- end
122
-
123
- def migrate_and_seed_database
124
- run_rake 'db:migrate db:seed'
125
- git_commit 'Update the database schema file'
126
- end
127
-
128
- def template_exist?(template)
129
- Exec::PROJECT_TEMPLATES.include?(template.to_sym)
130
- end
131
-
132
- private
133
-
134
- def exit_if_invalid_template
135
- template = @options[:template] || ''
136
-
137
- if template.length > 0
138
- log_task 'Check if template exists'
139
-
140
- unless template_exist?(template)
141
- log_error 'error', 'Cannot find template', 'message',
142
- "'#{template}' is not a valid template name",
143
- true do
144
- log_status_bottom 'tip',
145
- 'run `orats templates` to get a list of valid templates',
146
- :white
147
- end
148
-
149
- exit 1
150
- end
151
- end
152
- end
153
-
154
- def kill_spring_servers
155
- # rails generators will lock up if a spring server is running,
156
- # so kill them before continuing
157
- system 'pkill -f spring'
158
- end
159
- end
160
- end
161
- end
162
- end
@@ -1,57 +0,0 @@
1
- require 'socket'
2
- require 'timeout'
3
-
4
- module Orats
5
- module Commands
6
- module Project
7
- module Server
8
- START_COMMAND = 'bundle exec foreman start'
9
-
10
- def server_start
11
- @options[:skip_server_start] ? message = 'Start your' : message = 'Starting'
12
-
13
- puts '', '='*80
14
- log_status_top 'action', "#{message} server with the following commands", :cyan
15
- log_status_bottom 'command', "cd #{@active_path}", :magenta, true
16
- log_status_bottom 'command', START_COMMAND, :magenta
17
- puts '='*80, ''
18
-
19
- attempt_to_start unless @options[:skip_server_start]
20
- end
21
-
22
- private
23
-
24
- def attempt_to_start
25
- while port_taken? do
26
- log_status_top 'error', "Another application is using port 3000\n", :red
27
-
28
- exit 1 if no?('Would you like to try running the server again? (y/N)', :cyan)
29
- end
30
-
31
- puts
32
-
33
- run_from @active_path, START_COMMAND
34
- end
35
-
36
- def port_taken?
37
- begin
38
- Timeout::timeout(5) do
39
- begin
40
- s = TCPSocket.new('localhost', 3000)
41
- s.close
42
-
43
- return true
44
- rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
45
- return false
46
- end
47
- end
48
- rescue Timeout::Error
49
- false
50
- end
51
-
52
- false
53
- end
54
- end
55
- end
56
- end
57
- end
@@ -1,70 +0,0 @@
1
- require 'orats/commands/common'
2
- require 'orats/commands/project/rails'
3
-
4
- module Orats
5
- module Commands
6
- class Role < Common
7
- include Project::Rails
8
-
9
- def initialize(target_path = '', options = {})
10
- super
11
- end
12
-
13
- def init
14
- check_exit_conditions check_running_processes: false
15
- exit_if_invalid_role_name
16
-
17
- rails_template 'role'
18
- custom_rails_template unless @options[:custom].empty?
19
-
20
- repo_name = @options[:repo_name].empty? ? base_file_name :
21
- @options[:repo_name]
22
-
23
- log_task 'Update place holder repo name'
24
- gsub_file "#{@target_path}/README.md", 'repo_name',
25
- repo_name
26
- gsub_file "#{@target_path}/tests/main.yml", 'repo_name',
27
- repo_name
28
- git_commit 'Update place holder repo name'
29
-
30
- log_success
31
- end
32
-
33
- private
34
-
35
- def base_file_name
36
- File.basename(@target_path)
37
- end
38
-
39
- def exit_if_invalid_role_name
40
- log_task 'Check if role name is valid'
41
-
42
- unless base_file_name.count('.') == 1
43
- log_error 'error', 'Invalid role name', 'message',
44
- "'#{base_file_name}' is invalid, it must contain 1 period",
45
- true do
46
- log_status_bottom 'tip',
47
- 'Your role name should be github_user.role_name',
48
- :white
49
- end
50
-
51
- exit 1
52
- end
53
- end
54
-
55
- def log_success
56
- log_status_top 'success', 'Everything has been setup successfully',
57
- :cyan
58
- puts
59
- log_status_bottom 'question', 'What should you do next?', :yellow, true
60
- log_status_bottom 'answer', 'Check the readme in the role',
61
- :white
62
-
63
- log_status_bottom 'question', 'Are you new to ansible?', :yellow, true
64
- log_status_bottom 'answer',
65
- 'http://docs.ansible.com/intro_getting_started.html',
66
- :white
67
- end
68
- end
69
- end
70
- end