rhoconnect 3.4.5 → 4.0.0.beta.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (337) hide show
  1. data/CHANGELOG.md +57 -3
  2. data/Gemfile +9 -7
  3. data/Gemfile.lock +37 -37
  4. data/Rakefile +18 -7
  5. data/bench/benchapp/Gemfile +1 -1
  6. data/bench/benchapp/config.ru +0 -3
  7. data/bench/benchapp/controllers/ruby/application.rb +17 -0
  8. data/bench/benchapp/controllers/ruby/application_controller.rb +17 -0
  9. data/bench/benchapp/controllers/ruby/mock_adapter_controller.rb +8 -0
  10. data/bench/benchapp/controllers/ruby/queue_mock_adapter_controller.rb +8 -0
  11. data/bench/benchapp/{sources → models/ruby}/mock_adapter.rb +1 -1
  12. data/bench/benchapp/{sources → models/ruby}/queue_mock_adapter.rb +0 -0
  13. data/bench/benchapp/spec/{sources → models/ruby}/mock_adapter_spec.rb +1 -1
  14. data/bench/benchapp/spec/{sources → models/ruby}/queue_mock_adapter_spec.rb +1 -1
  15. data/bench/benchapp/spec/spec_helper.rb +2 -2
  16. data/bench/blobapp/Gemfile +1 -1
  17. data/bench/blobapp/config.ru +0 -3
  18. data/bench/blobapp/controllers/ruby/application_controller.rb +17 -0
  19. data/bench/blobapp/controllers/ruby/blob_adapter_controller.rb +8 -0
  20. data/bench/blobapp/{sources → models/ruby}/blob_adapter.rb +9 -2
  21. data/bench/blobapp/spec/{sources → models/ruby}/blob_adapter_spec.rb +1 -1
  22. data/bench/blobapp/spec/spec_helper.rb +1 -1
  23. data/bench/lib/bench/cli.rb +1 -1
  24. data/bench/scripts/blob_cud_script.rb +1 -1
  25. data/bench/scripts/query_md_script.rb +1 -1
  26. data/bench/scripts/query_only_script.rb +1 -1
  27. data/bench/scripts/query_script.rb +1 -1
  28. data/bench/scripts/test_query_script.rb +7 -1
  29. data/bench/spec/mock_adapter_spec.rb +1 -1
  30. data/bench/spec/result_spec.rb +3 -3
  31. data/bin/rhoconnect +5 -3
  32. data/commands/dtach/dtach_install.rb +2 -2
  33. data/commands/execute.rb +8 -3
  34. data/commands/generators/app.rb +3 -3
  35. data/commands/generators/controller.rb +6 -0
  36. data/commands/generators/model.rb +6 -0
  37. data/commands/generators/source.rb +3 -3
  38. data/commands/generators/update.rb +1 -1
  39. data/commands/redis/redis_about.rb +2 -2
  40. data/commands/redis/redis_download.rb +1 -1
  41. data/commands/redis/redis_install.rb +4 -3
  42. data/commands/redis/redis_restart.rb +4 -4
  43. data/commands/redis/redis_start.rb +5 -4
  44. data/commands/redis/redis_startbg.rb +5 -4
  45. data/commands/redis/redis_status.rb +13 -0
  46. data/commands/redis/redis_stop.rb +3 -3
  47. data/commands/rhoconnect/config.rb +28 -16
  48. data/commands/rhoconnect/flushdb.rb +1 -2
  49. data/commands/rhoconnect/get_token.rb +15 -11
  50. data/commands/rhoconnect/restart.rb +13 -5
  51. data/commands/rhoconnect/set_admin_password.rb +8 -8
  52. data/commands/rhoconnect/start.rb +74 -16
  53. data/commands/rhoconnect/startbg.rb +1 -1
  54. data/commands/rhoconnect/startdebug.rb +1 -1
  55. data/commands/rhoconnect/stop.rb +13 -1
  56. data/commands/rhoconnect/web.rb +5 -5
  57. data/commands/rhoconnect_console/console.rb +7 -5
  58. data/commands/{rhoconnect → rhoconnect_spec}/spec.rb +0 -0
  59. data/commands/rhoconnect_war/war.rb +9 -9
  60. data/commands/utilities/blank_app.ru +56 -0
  61. data/commands/utilities/redis_runner.rb +54 -19
  62. data/doc/authentication.txt +80 -6
  63. data/doc/blob-sync.txt +104 -97
  64. data/doc/bulk-sync.txt +1 -1
  65. data/doc/client-java.txt +3 -3
  66. data/doc/client-objc.txt +2 -2
  67. data/doc/client.txt +4 -4
  68. data/doc/command-line.txt +105 -200
  69. data/doc/data-partitioning.txt +40 -0
  70. data/doc/deploying.txt +249 -77
  71. data/doc/extending-rhoconnect-server.txt +40 -57
  72. data/doc/heroku-addon.txt +2 -0
  73. data/doc/install.txt +45 -95
  74. data/doc/introduction.txt +1 -1
  75. data/doc/java-plugin.txt +365 -190
  76. data/doc/metadata.txt +1 -1
  77. data/doc/migration.txt +108 -142
  78. data/doc/preparing-production.txt +1 -1
  79. data/doc/push-backend-setup.txt +2 -0
  80. data/doc/push-client-setup-android.txt +78 -0
  81. data/doc/push-client-setup-bb.txt +81 -0
  82. data/doc/push-client-setup-ios.txt +70 -0
  83. data/doc/push-client-setup-rps.txt +200 -0
  84. data/doc/push-client-setup.txt +63 -66
  85. data/doc/push-server-setup.txt +67 -40
  86. data/doc/push-testing.txt +29 -0
  87. data/doc/push.txt +21 -6
  88. data/doc/rest-api.txt +128 -55
  89. data/doc/rhoconnect-redis-stack.txt +120 -0
  90. data/doc/settings.txt +4 -12
  91. data/doc/source-adapters-intro.txt +28 -0
  92. data/doc/source-adapters.txt +235 -272
  93. data/doc/stats-middleware.txt +9 -29
  94. data/doc/supported-platforms.txt +21 -30
  95. data/doc/testing.txt +40 -42
  96. data/doc/tutorial.txt +72 -57
  97. data/examples/simple/Gemfile +1 -1
  98. data/examples/simple/application.rb +4 -5
  99. data/examples/simple/my_server.rb +2 -2
  100. data/examples/simple/settings/settings.yml +1 -1
  101. data/generators/rhoconnect.rb +151 -50
  102. data/generators/templates/application/Gemfile +1 -1
  103. data/generators/templates/application/Rakefile +3 -3
  104. data/generators/templates/application/config.ru +1 -4
  105. data/generators/templates/application/controllers/application_controller.rb +17 -0
  106. data/generators/templates/application/controllers/js/application_controller.js +14 -0
  107. data/generators/templates/application/controllers/ruby/application_controller.rb +17 -0
  108. data/generators/templates/application/package.json +8 -0
  109. data/generators/templates/application/rcgemfile +2 -5
  110. data/generators/templates/application/settings/settings.yml +3 -3
  111. data/generators/templates/application/spec/application_controller_spec.rb +23 -0
  112. data/generators/templates/application/spec/js_spec.rb +25 -0
  113. data/generators/templates/application/spec/spec_helper.rb +21 -7
  114. data/generators/templates/source/controllers/js/controller.js +7 -0
  115. data/generators/templates/source/controllers/ruby/controller.rb +8 -0
  116. data/generators/templates/source/controllers/ruby/controller_spec.rb +27 -0
  117. data/generators/templates/source/models/js/model.js +46 -0
  118. data/generators/templates/source/{source_adapter.rb → models/ruby/model.rb} +15 -10
  119. data/generators/templates/source/{source_spec.rb → models/ruby/model_spec.rb} +1 -1
  120. data/install.sh +5 -5
  121. data/installer/unix-like/create_texts.rb +2 -2
  122. data/installer/unix-like/rho_connect_install_constants.rb +2 -2
  123. data/installer/unix-like/rho_connect_install_utilities.rb +1 -1
  124. data/installer/utils/constants.rb +4 -4
  125. data/js-adapters/ballroom.js +216 -0
  126. data/js-adapters/node.rb +52 -0
  127. data/js-adapters/node_channel.rb +181 -0
  128. data/js-adapters/request.js +27 -0
  129. data/js-adapters/response.js +57 -0
  130. data/js-adapters/rhoconnect_helpers.js +60 -0
  131. data/js-adapters/router.js +60 -0
  132. data/js-adapters/server.js +5 -0
  133. data/lib/rhoconnect/api/app/ans_login.rb +3 -3
  134. data/lib/rhoconnect/api/app/bulk_data.rb +10 -10
  135. data/lib/rhoconnect/api/app/fast_delete.rb +11 -10
  136. data/lib/rhoconnect/api/app/fast_insert.rb +11 -10
  137. data/lib/rhoconnect/api/app/fast_update.rb +11 -10
  138. data/lib/rhoconnect/api/app/login.rb +5 -5
  139. data/lib/rhoconnect/api/app/push_deletes.rb +12 -11
  140. data/lib/rhoconnect/api/app/push_objects.rb +12 -11
  141. data/lib/rhoconnect/api/app/query.rb +8 -7
  142. data/lib/rhoconnect/api/app/queue_updates.rb +98 -94
  143. data/lib/rhoconnect/api/app/search.rb +8 -7
  144. data/lib/rhoconnect/api/client/client_get_db_doc.rb +5 -5
  145. data/lib/rhoconnect/api/client/client_set_db_doc.rb +8 -8
  146. data/lib/rhoconnect/api/client/create.rb +7 -7
  147. data/lib/rhoconnect/api/client/get_client_params.rb +4 -4
  148. data/lib/rhoconnect/api/client/list_client_docs.rb +17 -17
  149. data/lib/rhoconnect/api/client/register.rb +12 -12
  150. data/lib/rhoconnect/api/client/reset.rb +5 -5
  151. data/lib/rhoconnect/api/readstate/set_refresh_time.rb +9 -9
  152. data/lib/rhoconnect/api/source/get_source_params.rb +4 -4
  153. data/lib/rhoconnect/api/source/list_sources.rb +16 -16
  154. data/lib/rhoconnect/api/source/update_source_params.rb +6 -6
  155. data/lib/rhoconnect/api/store/get_db_doc.rb +4 -4
  156. data/lib/rhoconnect/api/store/set_db_doc.rb +7 -7
  157. data/lib/rhoconnect/api/system/get_adapter.rb +4 -4
  158. data/lib/rhoconnect/api/system/get_license_info.rb +8 -8
  159. data/lib/rhoconnect/api/system/login.rb +15 -15
  160. data/lib/rhoconnect/api/system/reset.rb +11 -11
  161. data/lib/rhoconnect/api/system/save_adapter.rb +4 -4
  162. data/lib/rhoconnect/api/system/stats.rb +22 -22
  163. data/lib/rhoconnect/api/user/create_user.rb +7 -7
  164. data/lib/rhoconnect/api/user/delete_client.rb +6 -6
  165. data/lib/rhoconnect/api/user/delete_user.rb +11 -10
  166. data/lib/rhoconnect/api/user/list_clients.rb +4 -4
  167. data/lib/rhoconnect/api/user/list_source_docs.rb +10 -10
  168. data/lib/rhoconnect/api/user/list_users.rb +3 -3
  169. data/lib/rhoconnect/api/user/ping.rb +3 -3
  170. data/lib/rhoconnect/api/user/show_user.rb +3 -3
  171. data/lib/rhoconnect/api/user/update_user.rb +5 -5
  172. data/lib/rhoconnect/api/user/user_get_db_doc.rb +5 -5
  173. data/lib/rhoconnect/api/user/user_set_db_doc.rb +10 -10
  174. data/lib/rhoconnect/api_token.rb +5 -6
  175. data/lib/rhoconnect/app.rb +6 -46
  176. data/lib/rhoconnect/application/init.rb +5 -2
  177. data/lib/rhoconnect/async.rb +76 -39
  178. data/lib/rhoconnect/bulk_data/bulk_data.rb +6 -4
  179. data/lib/rhoconnect/client.rb +59 -9
  180. data/lib/rhoconnect/condition/admin_required.rb +27 -0
  181. data/lib/rhoconnect/condition/client_required.rb +50 -0
  182. data/lib/rhoconnect/condition/login_required.rb +22 -0
  183. data/lib/rhoconnect/condition/source_required.rb +49 -0
  184. data/lib/rhoconnect/condition/verbs.rb +17 -0
  185. data/lib/rhoconnect/condition/verify_success.rb +19 -0
  186. data/lib/rhoconnect/controller/app_base.rb +74 -0
  187. data/lib/rhoconnect/controller/base.rb +68 -0
  188. data/lib/rhoconnect/controller/clients_controller.rb +79 -0
  189. data/lib/rhoconnect/controller/dynamic_adapter_controller.rb +93 -0
  190. data/lib/rhoconnect/controller/js_base.rb +124 -0
  191. data/lib/rhoconnect/controller/read_state_controller.rb +22 -0
  192. data/lib/rhoconnect/controller/source_adapter_base.rb +14 -0
  193. data/lib/rhoconnect/controller/sources_controller.rb +44 -0
  194. data/lib/rhoconnect/controller/store_controller.rb +25 -0
  195. data/lib/rhoconnect/controller/system_controller.rb +67 -0
  196. data/lib/rhoconnect/controller/users_controller.rb +99 -0
  197. data/lib/rhoconnect/db_adapter.rb +1 -3
  198. data/lib/rhoconnect/document.rb +159 -50
  199. data/lib/rhoconnect/handler/authenticate/execute_methods.rb +77 -0
  200. data/lib/rhoconnect/handler/authenticate/runner.rb +49 -0
  201. data/lib/rhoconnect/handler/authenticate.rb +3 -0
  202. data/lib/rhoconnect/handler/bulk_data.rb +28 -0
  203. data/lib/rhoconnect/handler/changes/engine.rb +271 -0
  204. data/lib/rhoconnect/handler/changes/execute_methods.rb +88 -0
  205. data/lib/rhoconnect/handler/changes/pass_through_runner.rb +11 -0
  206. data/lib/rhoconnect/handler/changes/runner.rb +53 -0
  207. data/lib/rhoconnect/handler/changes.rb +31 -0
  208. data/lib/rhoconnect/handler/helpers/auth_method.rb +29 -0
  209. data/lib/rhoconnect/handler/helpers/binding.rb +18 -0
  210. data/lib/rhoconnect/handler/helpers/bulk_data.rb +53 -0
  211. data/lib/rhoconnect/handler/helpers/source_job.rb +14 -0
  212. data/lib/rhoconnect/handler/helpers.rb +4 -0
  213. data/lib/rhoconnect/handler/plugin_callbacks/execute_methods.rb +99 -0
  214. data/lib/rhoconnect/handler/plugin_callbacks/runner.rb +28 -0
  215. data/lib/rhoconnect/handler/plugin_callbacks.rb +67 -0
  216. data/lib/rhoconnect/handler/query/engine.rb +93 -0
  217. data/lib/rhoconnect/handler/query/execute_methods.rb +21 -0
  218. data/lib/rhoconnect/handler/query/pass_through_runner.rb +35 -0
  219. data/lib/rhoconnect/handler/query/runner.rb +270 -0
  220. data/lib/rhoconnect/handler/query.rb +19 -0
  221. data/lib/rhoconnect/handler/search/engine.rb +60 -0
  222. data/lib/rhoconnect/handler/search/execute_methods.rb +32 -0
  223. data/lib/rhoconnect/handler/search/pass_through_runner.rb +18 -0
  224. data/lib/rhoconnect/handler/search/runner.rb +104 -0
  225. data/lib/rhoconnect/handler/search.rb +26 -0
  226. data/lib/rhoconnect/handler/sync.rb +29 -0
  227. data/lib/rhoconnect/jobs/source_job.rb +13 -4
  228. data/lib/rhoconnect/js_adapter.rb +79 -0
  229. data/lib/rhoconnect/license.rb +10 -2
  230. data/lib/rhoconnect/middleware/current_user.rb +14 -1
  231. data/lib/rhoconnect/middleware/helpers.rb +10 -93
  232. data/lib/rhoconnect/middleware/x_domain_session_wrapper.rb +1 -1
  233. data/lib/rhoconnect/model/base.rb +229 -0
  234. data/lib/rhoconnect/model/dynamic_adapter_model.rb +90 -0
  235. data/lib/rhoconnect/model/js_base.rb +121 -0
  236. data/lib/rhoconnect/ping/android.rb +1 -1
  237. data/lib/rhoconnect/predefined_adapters/bench_adapter.rb +7 -4
  238. data/lib/rhoconnect/read_state.rb +3 -3
  239. data/lib/rhoconnect/server.rb +159 -190
  240. data/lib/rhoconnect/source.rb +100 -11
  241. data/lib/rhoconnect/stats/record.rb +10 -10
  242. data/lib/rhoconnect/store.rb +905 -591
  243. data/lib/rhoconnect/{model.rb → store_orm.rb} +53 -115
  244. data/lib/rhoconnect/tasks.rb +18 -4
  245. data/lib/rhoconnect/test_methods.rb +30 -17
  246. data/lib/rhoconnect/user.rb +35 -17
  247. data/lib/rhoconnect/utilities.rb +1 -1
  248. data/lib/rhoconnect/version.rb +2 -2
  249. data/lib/rhoconnect/web-console/server.rb +29 -14
  250. data/lib/rhoconnect/web-console/views/home.js +10 -10
  251. data/lib/rhoconnect/web-console/views/new_ping.js +1 -1
  252. data/lib/rhoconnect.rb +120 -51
  253. data/rhoconnect.gemspec +4 -3
  254. data/spec/api/api_helper.rb +1 -6
  255. data/spec/api/app/fast_delete_spec.rb +4 -4
  256. data/spec/api/app/fast_insert_spec.rb +4 -4
  257. data/spec/api/app/fast_update_spec.rb +8 -8
  258. data/spec/api/app/push_deletes_spec.rb +2 -2
  259. data/spec/api/app/push_objects_spec.rb +5 -5
  260. data/spec/api/client/client_get_db_doc_spec.rb +6 -4
  261. data/spec/api/client/client_set_db_doc_spec.rb +3 -2
  262. data/spec/api/client/get_client_params_spec.rb +14 -0
  263. data/spec/api/client/list_client_docs_spec.rb +30 -20
  264. data/spec/api/client/reset_spec.rb +36 -0
  265. data/spec/api/source/get_source_params_spec.rb +23 -17
  266. data/spec/api/system/get_license_info_spec.rb +0 -20
  267. data/spec/api/system/login_spec.rb +8 -0
  268. data/spec/api/system/reset_spec.rb +0 -1
  269. data/spec/api/system/stats_spec.rb +5 -5
  270. data/spec/api/user/create_user_spec.rb +14 -6
  271. data/spec/api/user/delete_user_spec.rb +20 -18
  272. data/spec/api/user/list_users_spec.rb +5 -6
  273. data/spec/api/user/update_user_spec.rb +5 -4
  274. data/spec/apps/rhotestapp/config.ru +16 -1
  275. data/spec/apps/rhotestapp/controllers/js/js_sample_controller.js +23 -0
  276. data/spec/apps/rhotestapp/controllers/js/sample2_controller.js +32 -0
  277. data/spec/apps/rhotestapp/controllers/ruby/application_controller.rb +21 -0
  278. data/spec/apps/rhotestapp/controllers/ruby/sample_adapter_controller.rb +8 -0
  279. data/spec/apps/rhotestapp/models/js/js_sample.js +55 -0
  280. data/spec/apps/rhotestapp/models/js/sample2.js +25 -0
  281. data/spec/apps/rhotestapp/{sources → models/ruby}/base_adapter.rb +0 -0
  282. data/spec/apps/rhotestapp/{sources → models/ruby}/fixed_schema_adapter.rb +0 -0
  283. data/spec/apps/rhotestapp/{sources → models/ruby}/other_adapter.rb +0 -0
  284. data/spec/apps/rhotestapp/{sources → models/ruby}/sample_adapter.rb +0 -0
  285. data/spec/apps/rhotestapp/{sources → models/ruby}/simple_adapter.rb +2 -2
  286. data/spec/apps/rhotestapp/{sources → models/ruby}/sub_adapter.rb +0 -0
  287. data/spec/apps/rhotestapp/settings/settings.yml +0 -1
  288. data/spec/bulk_data/bulk_data_spec.rb +20 -5
  289. data/spec/cli/cli_spec.rb +83 -0
  290. data/spec/client_spec.rb +20 -17
  291. data/spec/client_sync_spec.rb +244 -406
  292. data/spec/controllers/js_base_spec.rb +89 -0
  293. data/spec/doc/doc_spec.rb +18 -18
  294. data/spec/document_spec.rb +29 -13
  295. data/spec/dynamic_adapter_spec.rb +6 -6
  296. data/spec/generator/generator_spec.rb +7 -4
  297. data/spec/jobs/bulk_data_job_spec.rb +14 -10
  298. data/spec/jobs/source_job_spec.rb +8 -8
  299. data/spec/license_spec.rb +5 -2
  300. data/spec/models/js_model_spec.rb +39 -0
  301. data/spec/node_spec.rb +42 -0
  302. data/spec/perf/store_perf_spec.rb +67 -12
  303. data/spec/ping/android_spec.rb +1 -1
  304. data/spec/read_state_spec.rb +1 -1
  305. data/spec/rhoconnect_spec.rb +1 -1
  306. data/spec/server/cors_spec.rb +14 -18
  307. data/spec/server/server_spec.rb +265 -88
  308. data/spec/server/stats_spec.rb +1 -1
  309. data/spec/source_adapter_spec.rb +54 -27
  310. data/spec/source_spec.rb +8 -3
  311. data/spec/source_sync_spec.rb +538 -468
  312. data/spec/spec_helper.rb +35 -4
  313. data/spec/stats/record_spec.rb +10 -10
  314. data/spec/{model_spec.rb → store_orm_spec.rb} +56 -54
  315. data/spec/store_spec.rb +159 -179
  316. data/spec/support/shared_examples.rb +36 -27
  317. data/spec/sync_states_spec.rb +40 -33
  318. data/spec/test_methods_spec.rb +18 -14
  319. data/spec/user_spec.rb +17 -30
  320. metadata +156 -52
  321. data/bench/benchapp/application.rb +0 -39
  322. data/bench/blobapp/application.rb +0 -44
  323. data/commands/rhoconnect/clean_start.rb +0 -9
  324. data/commands/rhoconnect/create_user.rb +0 -18
  325. data/commands/rhoconnect/delete_device.rb +0 -9
  326. data/commands/rhoconnect/delete_user.rb +0 -8
  327. data/commands/rhoconnect/reset.rb +0 -16
  328. data/commands/rhoconnect/reset_refresh.rb +0 -11
  329. data/generators/templates/application/application.rb +0 -43
  330. data/lib/rhoconnect/client_sync.rb +0 -434
  331. data/lib/rhoconnect/dynamic_adapter.rb +0 -91
  332. data/lib/rhoconnect/middleware/admin_user.rb +0 -23
  333. data/lib/rhoconnect/middleware/current_request.rb +0 -16
  334. data/lib/rhoconnect/middleware/login_required.rb +0 -22
  335. data/lib/rhoconnect/source_adapter.rb +0 -132
  336. data/lib/rhoconnect/source_sync.rb +0 -464
  337. data/spec/apps/rhotestapp/application.rb +0 -23
data/bin/rhoconnect CHANGED
@@ -1,14 +1,16 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env ruby -W0
2
2
  require 'rubygems'
3
+
3
4
  begin
4
5
  if File.exists?(File.join(Dir.pwd,'Gemfile'))
5
6
  require 'bundler'
6
7
  Bundler.require
7
8
  end
8
9
  $:.unshift File.join(File.dirname(__FILE__),'..')
10
+ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
9
11
  require 'templater'
10
12
  require 'generators/rhoconnect'
11
- require 'lib/rhoconnect'
13
+ require 'rhoconnect'
12
14
  require 'commands/execute'
13
15
 
14
16
  Execute.start
@@ -21,6 +23,6 @@ rescue Exception => e
21
23
  puts "See http://docs.rhomobile.com/rhoconnect/install#upgrading-an-existing-application about update details.\n\n"
22
24
  else
23
25
  puts "Run rhoconnect command error: #{e.inspect}"
26
+ puts e.backtrace.join("\n")
24
27
  end
25
28
  end
26
-
@@ -28,9 +28,9 @@ def fetch(uri_str, limit = 10)
28
28
  end
29
29
 
30
30
  Execute.define_task do
31
- desc 'dtach-install', 'Install dtach 0.8 from source'
31
+ desc 'dtach-install', 'Install dtach program from sources'
32
32
  def dtach_install
33
- invoke :dtach_about
33
+ dtach_about
34
34
 
35
35
  unless windows?
36
36
  Dir.chdir('/tmp/')
data/commands/execute.rb CHANGED
@@ -3,9 +3,7 @@
3
3
  require 'rubygems'
4
4
  require 'thor'
5
5
  require 'json'
6
- require 'zip/zip'
7
6
  require 'uri'
8
- require 'find'
9
7
  $:.unshift File.join(File.dirname(__FILE__), '.')
10
8
  $:.unshift File.join(File.dirname(__FILE__), '..')
11
9
  require 'lib/rhoconnect/utilities'
@@ -15,6 +13,13 @@ require 'utilities/redis_runner'
15
13
 
16
14
  include Utilities
17
15
 
16
+ settings_file = File.join(File.dirname(__FILE__), '..', 'generators', 'templates', 'application', 'settings', "settings.yml")
17
+ options = load_settings(settings_file)[Rhoconnect.environment]
18
+ RHOCONNECT_PORT = URI.parse(options[:syncserver]).port
19
+ REDIS_SERVER_URL = options[:redis]
20
+ PUSH_SERVER_URL = options[:push_server]
21
+ API_TOKEN = options[:api_token]
22
+
18
23
  class Execute < Thor
19
24
  no_tasks {
20
25
  def self.define_task(&block)
@@ -34,7 +39,7 @@ class Execute < Thor
34
39
  require 'bundler'
35
40
  tasks << 'rhoconnect_spec' if Bundler.load.specs.find{ |s| s.name == 'rspec' }
36
41
  end
37
-
42
+
38
43
  tasks.each do |dir|
39
44
  Dir.glob(File.join(File.dirname(__FILE__), "#{dir}", "*.rb")) do |file|
40
45
  require file
@@ -1,6 +1,6 @@
1
1
  Execute.define_task do
2
- desc "app NAME", "Generates a new rhoconnect application."
3
- def app(name)
4
- Rhoconnect.run_cli(Dir.pwd, 'thorhoconnect', Rhoconnect::VERSION, ARGV)
2
+ desc "app NAME [options]", "Generate a new rhoconnect application"
3
+ def app(name,platform=nil)
4
+ Rhoconnect.run_cli(Dir.pwd, 'rhoconnect', Rhoconnect::VERSION, ARGV)
5
5
  end #app
6
6
  end #do
@@ -0,0 +1,6 @@
1
+ Execute.define_task do
2
+ desc "source NAME", "Generate a new source adapter controller"
3
+ def controller(name,platform='ruby')
4
+ Rhoconnect.run_cli(Dir.pwd, 'thorhoconnect', Rhoconnect::VERSION, ARGV)
5
+ end #source
6
+ end #do
@@ -0,0 +1,6 @@
1
+ Execute.define_task do
2
+ desc "source NAME", "Generate a new source adapter model"
3
+ def model(name,platform='ruby')
4
+ Rhoconnect.run_cli(Dir.pwd, 'thorhoconnect', Rhoconnect::VERSION, ARGV)
5
+ end #model
6
+ end #do
@@ -1,6 +1,6 @@
1
1
  Execute.define_task do
2
- desc "source NAME", "Generates a new source adapter."
3
- def source(name)
4
- Rhoconnect.run_cli(Dir.pwd, 'thorhoconnect', Rhoconnect::VERSION, ARGV)
2
+ desc "source NAME [options]", "Generate a new source adapter"
3
+ def source(name,platform=nil)
4
+ Rhoconnect.run_cli(Dir.pwd, 'rhoconnect', Rhoconnect::VERSION, ARGV)
5
5
  end #source
6
6
  end #do
@@ -1,5 +1,5 @@
1
1
  Execute.define_task do
2
- desc "update", "Updates an existing application to the latest rhoconnect release."
2
+ desc "update", "Update an existing application to the latest rhoconnect release"
3
3
  def update
4
4
  Bundler.with_clean_env do
5
5
  `bundle install`
@@ -2,5 +2,5 @@ Execute.define_task do
2
2
  desc "redis-about", 'About redis'
3
3
  def redis_about
4
4
  puts "\nSee http://redis.io/ for information about redis.\n\n"
5
- end #about
6
- end #do
5
+ end
6
+ end
@@ -1,4 +1,4 @@
1
- REDIS_RELEASE = "2.4.10"
1
+ REDIS_RELEASE = "2.6.11"
2
2
  Execute.define_task do
3
3
  desc "redis-download", "Download redis release #{REDIS_RELEASE}"
4
4
  def redis_download
@@ -1,9 +1,10 @@
1
1
  Execute.define_task do
2
2
  desc "redis-install", 'Install the latest verison of Redis from Github (requires git, duh)'
3
3
  def redis_install
4
- invoke :redis_about
5
- invoke :redis_download
6
- invoke :redis_make
4
+ redis_about
5
+ redis_download
6
+ redis_make
7
+
7
8
  unless windows?
8
9
  ENV['PREFIX'] and bin_dir = "#{ENV['PREFIX']}/bin" or bin_dir = "#{RedisRunner.prefix}bin"
9
10
 
@@ -1,8 +1,8 @@
1
1
  Execute.define_task do
2
- desc "redis-restart", 'Restart redis'
2
+ desc "redis-restart", 'Restart redis on localhost'
3
3
  def redis_restart
4
- invoke :config
5
- RedisRunner.stop
6
- RedisRunner.start
4
+ redis_array = config[:redis]
5
+ RedisRunner.stop(redis_array)
6
+ RedisRunner.start(redis_array)
7
7
  end
8
8
  end
@@ -1,6 +1,7 @@
1
1
  Execute.define_task do
2
- desc "redis-start", 'Start redis'
2
+ desc "redis-start", 'Start redis on localhost'
3
3
  def redis_start
4
- RedisRunner.start
5
- end #redis_start
6
- end #do
4
+ redis_array = config[:redis]
5
+ RedisRunner.start(redis_array)
6
+ end
7
+ end
@@ -1,6 +1,7 @@
1
1
  Execute.define_task do
2
2
  desc "redis-startbg", "'Start redis' without dtach - for Rhostudio (internal)", :hide => true
3
- def redis_startbg
4
- RedisRunner.startbg
5
- end #redis_startbg
6
- end #do
3
+ def redis_startbg
4
+ redis_array = config[:redis]
5
+ RedisRunner.startbg(redis_array)
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ Execute.define_task do
2
+ desc "redis-status", 'Show status of redis servers'
3
+ def redis_status
4
+ config[:redis].each do |redis|
5
+ host,port = redis.split(':')[0..1]
6
+ if RedisRunner.running?(redis)
7
+ puts "#{host}:#{port}: server running"
8
+ else
9
+ puts "#{host}:#{port}: server not running"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,7 +1,7 @@
1
1
  Execute.define_task do
2
- desc "redis-stop", 'Stop redis'
2
+ desc "redis-stop", 'Stop redis running on localhost'
3
3
  def redis_stop
4
- invoke :config
5
- RedisRunner.stop
4
+ redis_array = config[:redis]
5
+ RedisRunner.stop(redis_array)
6
6
  end
7
7
  end
@@ -1,20 +1,32 @@
1
1
  Execute.define_task do
2
2
  desc "config", "Config", :hide => true
3
- def config
4
- $settings = load_settings(File.join('settings','settings.yml'))
5
- $env = (ENV['RHO_ENV'] || ENV['RACK_ENV'] || :development).to_sym
6
-
7
- uri = URI.parse($settings[$env][:syncserver])
8
- $url = "#{uri.scheme}://#{uri.host}"
9
- $url = "#{$url}:#{uri.port}" if uri.port && uri.port != 80
10
- $host = uri.host
11
- $port = uri.port
12
- $appname = $settings[$env][:syncserver].split('/').last
13
- $token_file = File.join(ENV['HOME'],'.rhoconnect_token')
14
- $token = File.read($token_file) if File.exist?($token_file)
15
- # Redis options
16
- redis_server = $settings[$env][:redis]
17
- host, port, db, password = redis_server.split(':')
18
- $redis_options = { :host => host, :port => port, :db => db, :password => password }
3
+ def config(settings_file=false)
4
+ if File.exist?(File.join('settings','settings.yml'))
5
+ settings = load_settings(File.join('settings','settings.yml'))
6
+ rackup_config = "config.ru"
7
+ elsif settings_file
8
+ settings = load_settings(settings_file)
9
+ rackup_config = File.join(File.dirname(__FILE__), '..', 'utilities', 'blank_app.ru')
10
+ elsif File.exist?(File.join(ENV['HOME'], '.rhoconnect.yml'))
11
+ settings = load_settings(File.join(ENV['HOME'], '.rhoconnect.yml'))
12
+ rackup_config = File.join(File.dirname(__FILE__), '..', 'utilities', 'blank_app.ru')
13
+ else
14
+ options = { :syncserver => "http://localhost:#{RHOCONNECT_PORT}",
15
+ :redis => REDIS_SERVER_URL, :push_server => PUSH_SERVER_URL, :api_token => API_TOKEN }
16
+ settings = { :development => options, :test => options, :production => options }
17
+ rackup_config = File.join(File.dirname(__FILE__), '..', 'utilities', 'blank_app.ru')
18
+ end
19
+ settings = settings[Rhoconnect.environment]
20
+ # syncserver settings
21
+ uri = URI.parse(settings[:syncserver])
22
+ port = uri.port unless port
23
+ url = "#{uri.scheme}://#{uri.host}:#{port}"
24
+ settings[:syncserver] = url
25
+ settings[:rackup] = rackup_config
26
+ # redis settings
27
+ redis_conf = settings[:redis]
28
+ settings[:redis] = [redis_conf] if redis_conf.is_a?(String)
29
+
30
+ settings
19
31
  end
20
32
  end
@@ -1,11 +1,10 @@
1
1
  Execute.define_task do
2
2
  desc "flushdb", "Flush data store - WARNING: THIS REMOVES ALL DATA IN RHOCONNECT"
3
3
  def flushdb
4
- invoke :config
5
4
  puts "*** WARNING: THIS WILL REMOVE ALL DATA FROM YOUR REDIS STORE ***"
6
5
  confirm = ask "Are you sure (please answer yes/no)? "
7
6
  if confirm == 'yes'
8
- RedisRunner.flushdb
7
+ RedisRunner.flushdb(config[:redis])
9
8
  puts "Database flushed..."
10
9
  else
11
10
  puts "Aborted..."
@@ -1,12 +1,11 @@
1
1
  Execute.define_task do
2
- desc "get-token", "Fetches current api token from rhoconnect"
3
- def get_token
4
- invoke :config
2
+ desc "get-token", "Fetch current api token from rhoconnect"
3
+ def get_token(save = true)
4
+ url = config[:syncserver]
5
5
  password = ''
6
- login = ask "admin login: "
7
6
  begin
8
7
  system "stty -echo"
9
- password = ask "\nadmin password: "
8
+ password = ask "admin password: "
10
9
  system "stty echo"
11
10
  rescue NoMethodError, Interrupt
12
11
  system "stty echo"
@@ -14,12 +13,17 @@ desc "get-token", "Fetches current api token from rhoconnect"
14
13
  end
15
14
  puts ''
16
15
  begin
17
- $token = RestClient.post("#{$url}/api/admin/login", { :login => login, :password => password})
16
+ token = RestClient.post("#{url}/rc/v1/system/login",
17
+ { :login => 'rhoadmin', :password => password }.to_json, :content_type => :json)
18
18
  rescue
19
- puts "Login failed."
19
+ puts "Rhoconnect server is not running or invalid credentials."
20
20
  exit
21
21
  end
22
- File.open($token_file,'w') {|f| f.write $token}
23
- puts "Token is saved in: #{$token_file}"
24
- end #get_token
25
- end #do
22
+ if save
23
+ token_file = File.join(ENV['HOME'],'.rhoconnect_token')
24
+ File.open(token_file,'w') {|f| f.write(token)}
25
+ puts "Token is saved in: #{token_file}"
26
+ end
27
+ token
28
+ end
29
+ end
@@ -1,7 +1,15 @@
1
1
  Execute.define_task do
2
- desc "restart", "Alias for `rhoconnect stop; rhoconnect start`"
2
+ desc "restart [options]", "Alias for `rhoconnect stop; rhoconnect start`"
3
+ method_option :port, :aliases => "-p", :type => :numeric, :desc => "Use port (default: #{RHOCONNECT_PORT})"
4
+ method_option :redis, :aliases => "-r", :type => :string, :desc => "Redis server settings: (default: #{REDIS_SERVER_URL})"
5
+ method_option :push_server, :aliases => "-P", :type => :string, :desc => "Push server settings (default: #{PUSH_SERVER_URL})"
6
+ method_option :api_token, :aliases => "-t", :type => :string, :desc => "API token (default: #{API_TOKEN})"
7
+ method_option :config, :aliases => "-f", :type => :string, :desc => "/path/to/rhoconnect/settings.yml file"
8
+ method_option :licenseflie, :aliases => "-l", :type => :string, :desc => "/path/to/license.key file"
3
9
  def restart
4
- invoke :stop
5
- invoke :start
6
- end #restart
7
- end #do
10
+ puts "Stop rhoconnect server ..."
11
+ stop
12
+ puts "Start rhoconnect server ..."
13
+ start options
14
+ end
15
+ end
@@ -1,7 +1,7 @@
1
1
  Execute.define_task do
2
- desc "set-admin-password", "Sets the admin password"
2
+ desc "set-admin-password", "Set the admin password"
3
3
  def set_admin_password
4
- invoke :get_token
4
+ token = get_token(false)
5
5
  new_pass,new_pass_confirm = '',''
6
6
  begin
7
7
  system "stty -echo"
@@ -16,11 +16,11 @@ Execute.define_task do
16
16
  puts "\nNew password can't be empty."
17
17
  elsif new_pass == new_pass_confirm
18
18
  puts ""
19
- RestClient.post("#{$url}/api/user/update_user", { :app_name => $appname,
20
- :api_token => $token,
21
- :attributes => { :new_password => new_pass } })
19
+ url = config[:syncserver]
20
+ RestClient.put("#{url}/rc/v1/users/rhoadmin",
21
+ { :attributes => { :new_password => new_pass }}.to_json, {:content_type => :json, 'X-RhoConnect-API-TOKEN' => token})
22
22
  else
23
23
  puts "\nNew password and confirmation must match."
24
- end #if
25
- end #set_admin_password
26
- end #do
24
+ end
25
+ end
26
+ end
@@ -1,26 +1,84 @@
1
1
  Execute.define_task do
2
- desc "start", "Start rhoconnect server"
3
- def start
4
- invoke :config
5
- unless RedisRunner.running?
6
- redis_config = "#{$redis_options[:host]}:#{$redis_options[:port]}"
7
- puts "Redis is not running on #{redis_config}. Please start it by running 'rhoconnect redis-start' command."
8
- exit
9
- end
10
- command = (jruby?) ? trinidad? : (thin? || mongrel? || report_missing_server)
11
- if windows?
12
- puts 'Starting rhoconnect...'
13
- system "#{command} config.ru -P #{rhoconnect_pid}"
14
- elsif jruby?
2
+ desc "start [options]", "Start rhoconnect server"
3
+ method_option :port, :aliases => "-p", :type => :numeric, :desc => "Use port (default: #{RHOCONNECT_PORT})"
4
+ method_option :redis, :aliases => "-r", :type => :string, :desc => "Redis server settings: (default: #{REDIS_SERVER_URL})"
5
+ method_option :push_server, :aliases => "-P", :type => :string, :desc => "Push server settings (default: #{PUSH_SERVER_URL})"
6
+ method_option :api_token, :aliases => "-t", :type => :string, :desc => "API token (default: #{API_TOKEN})"
7
+ method_option :config, :aliases => "-f", :type => :string, :desc => "/path/to/rhoconnect/settings.yml file"
8
+ method_option :licenseflie, :aliases => "-l", :type => :string, :desc => "/path/to/license.key file"
9
+ def start(params = {})
10
+ # if this command called from 'restart', then params not emply
11
+ params = options if params.empty?
12
+
13
+ if options[:config] # -f settings.yml
14
+ unless File.exist?(options[:config])
15
+ puts "#{options[:config]}: No such file"
16
+ exit(-1)
17
+ end
18
+ end
19
+ if options[:licenseflie] # -l license.key
20
+ unless File.exist?(params[:licenseflie])
21
+ puts "#{options[:licenseflie]}: No such file"
22
+ exit(-1)
23
+ end
24
+ licensefile = File.expand_path(options[:licenseflie])
25
+ end
26
+ settings = config(options[:config])
27
+
28
+ port = (params[:port]) ? params[:port] : URI.parse(settings[:syncserver]).port
29
+
30
+ redis_url = (params[:redis]) ? params[:redis] : settings[:redis]
31
+ redis_url = [redis_url] if redis_url.is_a?(String)
32
+ start_list = []
33
+ redis_url.each do |redis_inst|
34
+ start_list << redis_inst unless RedisRunner.running?(redis_inst)
35
+ end
36
+ RedisRunner.startbg(start_list) unless start_list.empty?
37
+
38
+ if File.exist?(File.join('settings','settings.yml'))
39
+ # If command running frorm app directory, then do't touch "~/.rhoconnect.yml"
40
+ else
41
+ unless File.exist?(File.join(ENV['HOME'], '.rhoconnect.yml'))
42
+ push_server = (params[:push_server]) ? params[:push_server] : PUSH_SERVER_URL
43
+ token = (params[:api_token]) ? params[:api_token] : API_TOKEN
44
+ options = { :syncserver => "http://localhost:#{port}", :redis => redis_url,
45
+ :push_server => push_server, :api_token => token }
46
+ options[:licensefile] = licensefile if licensefile
47
+ options[:secret] = SecureRandom.hex(64)
48
+ conf_hash = { :development => options, :test => options, :production => options }
49
+ File.open(File.join(ENV['HOME'], '.rhoconnect.yml'), 'w') { |f| f.write(conf_hash.to_yaml) }
50
+ end
51
+ end
52
+
53
+ command = "bundle exec rackup -s #{defined?(JRUBY_VERSION) ? 'puma' : 'thin'}"
54
+ rackup_config = settings[:rackup]
55
+ command.sub!(/bundle exec /, '') if(rackup_config != "config.ru")
56
+ # Set environment varialbes: 'API_TOKEN', 'REDIS_URL', 'RHOCONNECT_LICENSE'
57
+ env = {}
58
+ if params[:api_token]
59
+ env["API_TOKEN"] = params[:api_token]
60
+ end
61
+ if params[:redis]
62
+ env["REDIS_URL"] = params[:redis]
63
+ end
64
+ if licensefile
65
+ license = IO.read(licensefile).strip
66
+ env["RHOCONNECT_LICENSE"] = license
67
+ end
68
+
69
+ if jruby?
15
70
  puts 'Starting rhoconnect in jruby environment...'
16
- system "#{command}"
71
+ system(env, "#{command} --port #{port} -P #{rhoconnect_pid} #{rackup_config}")
72
+ elsif windows?
73
+ puts 'Starting rhoconnect...'
74
+ system(env, "#{command} --port #{port} -P #{rhoconnect_pid} #{rackup_config}")
17
75
  else
18
76
  if dtach_installed?
19
77
  puts 'Detach with Ctrl+\ Re-attach with rhoconnect attach'
20
78
  sleep 2
21
- cmd "dtach -A #{rhoconnect_socket} #{command} config.ru -P #{rhoconnect_pid}"
79
+ system(env, "dtach -A #{rhoconnect_socket} #{command} --port #{port} -P #{rhoconnect_pid} #{rackup_config}")
22
80
  else
23
- cmd "#{command} config.ru -P #{rhoconnect_pid}"
81
+ system(env, "#{command} --port #{port} -P #{rhoconnect_pid} #{rackup_config}")
24
82
  end
25
83
  end
26
84
  end
@@ -17,7 +17,7 @@ Execute.define_task do
17
17
  system "#{cmd} config.ru -P #{rhoconnect_pid}"
18
18
  elsif jruby?
19
19
  puts 'Starting rhoconnect in jruby environment...'
20
- system "#{cmd}"
20
+ system "#{cmd} -r config.ru"
21
21
  else
22
22
  system "#{cmd} config.ru -P #{rhoconnect_pid}"
23
23
  end
@@ -18,7 +18,7 @@ Execute.define_task do
18
18
  system "#{cmd} config.ru -P #{rhoconnect_pid}"
19
19
  elsif jruby?
20
20
  puts 'Starting rhoconnect in jruby environment...'
21
- system "#{cmd}"
21
+ system "#{cmd} -r config.ru"
22
22
  else
23
23
  system "#{cmd} config.ru -P #{rhoconnect_pid}"
24
24
  end
@@ -4,7 +4,19 @@ Execute.define_task do
4
4
  if windows?
5
5
  File.delete "#{rhoconnect_pid}" if system("FOR /F %A in (#{rhoconnect_pid}) do taskkill /F /PID %A")
6
6
  else
7
- cmd "cat #{rhoconnect_pid} | xargs kill -3"
7
+ if File.exist?("#{rhoconnect_pid}")
8
+ pid = `cat #{rhoconnect_pid}`
9
+ puts "Sending a QUIT signal to process #{pid}"
10
+ system "kill -3 #{pid}"
11
+ 3.times do
12
+ sleep 1
13
+ return if !File.exist?("#{rhoconnect_pid}")
14
+ end
15
+
16
+ puts "Process #{pid} is still running. Sending a KILL signal to it ..."
17
+ system "kill -9 #{pid}"
18
+ File.delete(rhoconnect_pid)
19
+ end
8
20
  end
9
21
  end
10
22
  end
@@ -1,7 +1,7 @@
1
1
  Execute.define_task do
2
- desc "web", "Launch the web console in a browser - uses :syncserver: in settings.yml"
2
+ desc "web", "Launch the web console in a browser"
3
3
  def web
4
- invoke :config
5
- windows? ? system("start #{$url}") : system("open #{$url}")
6
- end #web
7
- end #do
4
+ url = config[:syncserver]
5
+ windows? ? system("start #{url}") : system("open #{url}")
6
+ end
7
+ end
@@ -1,16 +1,18 @@
1
1
  Execute.define_task do
2
- desc "console [environment]", "run rhoconnect console"
2
+ desc "console [environment]", "Run rhoconnect console"
3
3
  def console(environment=nil)
4
4
  ENV['RACK_ENV'] = environment || 'development'
5
- application_file = ruby19? ? './application' : 'application'
6
- invoke :config
5
+ application_file = (File.exist?(File.join(Dir.pwd, 'application.rb'))) ?
6
+ File.join(Dir.pwd, 'application.rb') :
7
+ File.join(File.dirname(__FILE__), '..', '..', 'generators', 'templates', 'application', 'application.rb')
8
+
9
+ redis_url = config[:redis]
7
10
  if RedisRunner.running?
8
11
  system "irb -rubygems -r #{File.join(File.dirname(__FILE__),'console_helper')} " +
9
12
  "-r #{File.join(File.dirname(__FILE__), '..', '..', 'lib', 'rhoconnect') } " +
10
13
  "-r #{application_file}"
11
14
  else
12
- redis_config = "#{$redis_options[:host]}:#{$redis_options[:port]}"
13
- puts "Redis is not running on #{redis_config}. Please start it by running 'rhoconnect redis-start' command."
15
+ puts "Redis is not running on #{redis_url}. Please start it by running 'rhoconnect redis-start' command."
14
16
  end
15
17
  end
16
18
  end
File without changes
@@ -11,22 +11,22 @@ Execute.define_task do
11
11
  if aFile
12
12
  includeDirs = FileList['*'].exclude do |entry|
13
13
  entry if (not File.directory? entry) || (entry == 'spec')
14
- end #if
14
+ end
15
15
  configFile = "Warbler::Config.new do |config|\n" +
16
- "config.dirs = %w(#{includeDirs.join(' ')})\n" +
17
- "config.includes = FileList[\"./*\"]\n" +
18
- "config.excludes = FileList[\"./*.war\",'spec']\nend"
16
+ " config.dirs = %w(#{includeDirs.join(' ')})\n" +
17
+ " config.includes = FileList[\"./*\", \".rcgemfile\"]\n" +
18
+ " config.excludes = FileList[\"./*.war\",'spec']\nend"
19
19
  aFile.write("#{configFile}")
20
20
  aFile.close
21
21
  else
22
22
  puts "Unable to create config/warble.rb file!"
23
- end #if
24
- end #if
23
+ end
24
+ end
25
25
  # build the executable WAR using the config/warble.rb file
26
26
  ENV['BUNDLE_WITHOUT'] = ['development','test'].join(':')
27
27
  system 'bundle exec warble executable war'
28
28
  else
29
29
  puts "Cannot build WAR files outside of JRuby environment!"
30
- end #if
31
- end #war
32
- end #do
30
+ end
31
+ end
32
+ end