MuranoCLI 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +21 -0
  5. data/Gemfile +27 -0
  6. data/LICENSE.txt +19 -0
  7. data/MuranoCLI.gemspec +50 -0
  8. data/MuranoCLI.iss +50 -0
  9. data/README.markdown +208 -0
  10. data/Rakefile +188 -0
  11. data/TODO.taskpaper +122 -0
  12. data/bin/mr +8 -0
  13. data/bin/murano +84 -0
  14. data/docs/demo.md +109 -0
  15. data/lib/MrMurano/Account.rb +211 -0
  16. data/lib/MrMurano/Config-Migrate.rb +47 -0
  17. data/lib/MrMurano/Config.rb +286 -0
  18. data/lib/MrMurano/Mock.rb +63 -0
  19. data/lib/MrMurano/Product-1P-Device.rb +145 -0
  20. data/lib/MrMurano/Product-Resources.rb +195 -0
  21. data/lib/MrMurano/Product.rb +358 -0
  22. data/lib/MrMurano/ProjectFile.rb +349 -0
  23. data/lib/MrMurano/Solution-Cors.rb +46 -0
  24. data/lib/MrMurano/Solution-Endpoint.rb +177 -0
  25. data/lib/MrMurano/Solution-File.rb +150 -0
  26. data/lib/MrMurano/Solution-ServiceConfig.rb +140 -0
  27. data/lib/MrMurano/Solution-Services.rb +326 -0
  28. data/lib/MrMurano/Solution-Users.rb +129 -0
  29. data/lib/MrMurano/Solution.rb +59 -0
  30. data/lib/MrMurano/SubCmdGroupContext.rb +49 -0
  31. data/lib/MrMurano/SyncUpDown.rb +565 -0
  32. data/lib/MrMurano/commands/assign.rb +57 -0
  33. data/lib/MrMurano/commands/businessList.rb +45 -0
  34. data/lib/MrMurano/commands/completion.rb +152 -0
  35. data/lib/MrMurano/commands/config.rb +67 -0
  36. data/lib/MrMurano/commands/content.rb +130 -0
  37. data/lib/MrMurano/commands/cors.rb +30 -0
  38. data/lib/MrMurano/commands/domain.rb +17 -0
  39. data/lib/MrMurano/commands/gb.rb +33 -0
  40. data/lib/MrMurano/commands/init.rb +138 -0
  41. data/lib/MrMurano/commands/keystore.rb +157 -0
  42. data/lib/MrMurano/commands/logs.rb +78 -0
  43. data/lib/MrMurano/commands/mock.rb +63 -0
  44. data/lib/MrMurano/commands/password.rb +88 -0
  45. data/lib/MrMurano/commands/postgresql.rb +41 -0
  46. data/lib/MrMurano/commands/product.rb +14 -0
  47. data/lib/MrMurano/commands/productCreate.rb +39 -0
  48. data/lib/MrMurano/commands/productDelete.rb +33 -0
  49. data/lib/MrMurano/commands/productDevice.rb +84 -0
  50. data/lib/MrMurano/commands/productDeviceIdCmds.rb +86 -0
  51. data/lib/MrMurano/commands/productList.rb +45 -0
  52. data/lib/MrMurano/commands/productWrite.rb +27 -0
  53. data/lib/MrMurano/commands/show.rb +80 -0
  54. data/lib/MrMurano/commands/solution.rb +14 -0
  55. data/lib/MrMurano/commands/solutionCreate.rb +39 -0
  56. data/lib/MrMurano/commands/solutionDelete.rb +34 -0
  57. data/lib/MrMurano/commands/solutionList.rb +45 -0
  58. data/lib/MrMurano/commands/status.rb +92 -0
  59. data/lib/MrMurano/commands/sync.rb +60 -0
  60. data/lib/MrMurano/commands/timeseries.rb +115 -0
  61. data/lib/MrMurano/commands/tsdb.rb +271 -0
  62. data/lib/MrMurano/commands/usage.rb +23 -0
  63. data/lib/MrMurano/commands/zshcomplete.erb +112 -0
  64. data/lib/MrMurano/commands.rb +32 -0
  65. data/lib/MrMurano/hash.rb +20 -0
  66. data/lib/MrMurano/http.rb +153 -0
  67. data/lib/MrMurano/makePretty.rb +75 -0
  68. data/lib/MrMurano/schema/pf-v1.0.0.yaml +114 -0
  69. data/lib/MrMurano/schema/sf-v0.2.0.yaml +77 -0
  70. data/lib/MrMurano/schema/sf-v0.3.0.yaml +78 -0
  71. data/lib/MrMurano/template/mock.erb +9 -0
  72. data/lib/MrMurano/template/projectFile.murano.erb +81 -0
  73. data/lib/MrMurano/verbosing.rb +99 -0
  74. data/lib/MrMurano/version.rb +4 -0
  75. data/lib/MrMurano.rb +20 -0
  76. data/spec/Account-Passwords_spec.rb +242 -0
  77. data/spec/Account_spec.rb +272 -0
  78. data/spec/ConfigFile_spec.rb +50 -0
  79. data/spec/ConfigMigrate_spec.rb +89 -0
  80. data/spec/Config_spec.rb +409 -0
  81. data/spec/Http_spec.rb +204 -0
  82. data/spec/MakePretties_spec.rb +118 -0
  83. data/spec/Mock_spec.rb +53 -0
  84. data/spec/ProductBase_spec.rb +113 -0
  85. data/spec/ProductContent_spec.rb +162 -0
  86. data/spec/ProductResources_spec.rb +329 -0
  87. data/spec/Product_1P_Device_spec.rb +202 -0
  88. data/spec/Product_1P_RPC_spec.rb +175 -0
  89. data/spec/Product_spec.rb +153 -0
  90. data/spec/ProjectFile_spec.rb +324 -0
  91. data/spec/Solution-Cors_spec.rb +164 -0
  92. data/spec/Solution-Endpoint_spec.rb +581 -0
  93. data/spec/Solution-File_spec.rb +212 -0
  94. data/spec/Solution-ServiceConfig_spec.rb +202 -0
  95. data/spec/Solution-ServiceDevice_spec.rb +176 -0
  96. data/spec/Solution-ServiceEventHandler_spec.rb +385 -0
  97. data/spec/Solution-ServiceModules_spec.rb +465 -0
  98. data/spec/Solution-UsersRoles_spec.rb +207 -0
  99. data/spec/Solution_spec.rb +92 -0
  100. data/spec/SyncRoot_spec.rb +83 -0
  101. data/spec/SyncUpDown_spec.rb +495 -0
  102. data/spec/Verbosing_spec.rb +279 -0
  103. data/spec/_workspace.rb +27 -0
  104. data/spec/cmd_assign_spec.rb +51 -0
  105. data/spec/cmd_business_spec.rb +59 -0
  106. data/spec/cmd_common.rb +72 -0
  107. data/spec/cmd_config_spec.rb +68 -0
  108. data/spec/cmd_content_spec.rb +71 -0
  109. data/spec/cmd_cors_spec.rb +50 -0
  110. data/spec/cmd_device_spec.rb +96 -0
  111. data/spec/cmd_domain_spec.rb +32 -0
  112. data/spec/cmd_init_spec.rb +30 -0
  113. data/spec/cmd_keystore_spec.rb +97 -0
  114. data/spec/cmd_password_spec.rb +62 -0
  115. data/spec/cmd_status_spec.rb +239 -0
  116. data/spec/cmd_syncdown_spec.rb +86 -0
  117. data/spec/cmd_syncup_spec.rb +62 -0
  118. data/spec/cmd_usage_spec.rb +36 -0
  119. data/spec/fixtures/.mrmuranorc +9 -0
  120. data/spec/fixtures/ProjectFiles/invalid.yaml +9 -0
  121. data/spec/fixtures/ProjectFiles/only_meta.yaml +24 -0
  122. data/spec/fixtures/ProjectFiles/with_routes.yaml +27 -0
  123. data/spec/fixtures/SolutionFiles/0.2.0.json +20 -0
  124. data/spec/fixtures/SolutionFiles/0.2.0_invalid.json +18 -0
  125. data/spec/fixtures/SolutionFiles/0.2.json +21 -0
  126. data/spec/fixtures/SolutionFiles/0.3.0.json +20 -0
  127. data/spec/fixtures/SolutionFiles/0.3.0_invalid.json +19 -0
  128. data/spec/fixtures/SolutionFiles/0.3.json +20 -0
  129. data/spec/fixtures/SolutionFiles/basic.json +20 -0
  130. data/spec/fixtures/SolutionFiles/secret.json +6 -0
  131. data/spec/fixtures/configfile +9 -0
  132. data/spec/fixtures/dumped_config +42 -0
  133. data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
  134. data/spec/fixtures/mrmuranorc_tool_bob +3 -0
  135. data/spec/fixtures/product_spec_files/example.exoline.spec.yaml +116 -0
  136. data/spec/fixtures/product_spec_files/example.murano.spec.yaml +14 -0
  137. data/spec/fixtures/product_spec_files/gwe.exoline.spec.yaml +21 -0
  138. data/spec/fixtures/product_spec_files/gwe.murano.spec.yaml +16 -0
  139. data/spec/fixtures/product_spec_files/lightbulb-no-state.yaml +11 -0
  140. data/spec/fixtures/product_spec_files/lightbulb.yaml +14 -0
  141. data/spec/fixtures/roles-three.yaml +11 -0
  142. data/spec/fixtures/syncable_content/assets/icon.png +0 -0
  143. data/spec/fixtures/syncable_content/assets/index.html +0 -0
  144. data/spec/fixtures/syncable_content/assets/js/script.js +0 -0
  145. data/spec/fixtures/syncable_content/modules/table_util.lua +58 -0
  146. data/spec/fixtures/syncable_content/routes/manyRoutes.lua +11 -0
  147. data/spec/fixtures/syncable_content/routes/singleRoute.lua +5 -0
  148. data/spec/fixtures/syncable_content/services/devdata.lua +18 -0
  149. data/spec/fixtures/syncable_content/services/timers.lua +4 -0
  150. data/spec/spec_helper.rb +119 -0
  151. metadata +498 -0
@@ -0,0 +1,36 @@
1
+ require 'fileutils'
2
+ require 'open3'
3
+ require 'pathname'
4
+ require 'cmd_common'
5
+
6
+ RSpec.describe 'murano usage', :cmd, :needs_password do
7
+ include_context "CI_CMD"
8
+
9
+ before(:example) do
10
+ @project_name = rname('usageTest')
11
+ out, err, status = Open3.capture3(capcmd('murano', 'solution', 'create', @project_name, '--save'))
12
+ expect(err).to eq('')
13
+ expect(out.chomp).to match(/^[a-zA-Z0-9]+$/)
14
+ expect(status.exitstatus).to eq(0)
15
+ end
16
+ after(:example) do
17
+ out, err, status = Open3.capture3(capcmd('murano', 'solution', 'delete', @project_name))
18
+ expect(out).to eq('')
19
+ expect(err).to eq('')
20
+ expect(status.exitstatus).to eq(0)
21
+ end
22
+
23
+ it "show usage" do
24
+ out, err, status = Open3.capture3(capcmd('murano', 'usage'))
25
+ expect(err).to eq('')
26
+ olines = out.lines
27
+ expect(olines[0]).to match(/^(\+-+){5}\+$/)
28
+ expect(olines[1]).to match(/^\|\s+\| Quota\s+\| Daily\s+\| Monthly\s+\| Total\s+\|$/)
29
+ expect(olines[2]).to match(/^(\+-+){5}\+$/)
30
+ expect(olines[-1]).to match(/^(\+-+){5}\+$/)
31
+ expect(status.exitstatus).to eq(0)
32
+ end
33
+
34
+ end
35
+
36
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,9 @@
1
+ [solution]
2
+ id = XXXXXXXXXX
3
+
4
+ [doThisTest]
5
+ bob = build
6
+
7
+ [s-fDEADBEEFGAEG]
8
+ spec = bobo.yaml
9
+
@@ -0,0 +1,9 @@
1
+ ---
2
+ info:
3
+ name: tested
4
+ summary: My little test project
5
+ authors: ["a person with <an@email.address>"]
6
+ version: 1.56.12
7
+ routes:
8
+ include: custom_api.lua
9
+ formatversion: 1.0.0
@@ -0,0 +1,24 @@
1
+ ---
2
+ # First up is some metadata about this project.
3
+ info:
4
+ # Nice short and easy. Also must be a valid domain name component.
5
+ name: tested
6
+
7
+ # Short one line summary of this project.
8
+ summary: My little test project
9
+
10
+ # Longer, multiple paragraph explanation.
11
+ description: |
12
+ There is a lot to say about my little project.
13
+
14
+ But I am not saying any of it right now.
15
+
16
+
17
+ # Who made this
18
+ authors: ["a person with <an@email.address>"]
19
+
20
+ # The version of the Project
21
+ version: 1.56.12
22
+
23
+
24
+ formatversion: 1.0.0
@@ -0,0 +1,27 @@
1
+ ---
2
+ # First up is some metadata about this project.
3
+ info:
4
+ # Nice short and easy. Also must be a valid domain name component.
5
+ name: tested
6
+
7
+ # Short one line summary of this project.
8
+ summary: My little test project
9
+
10
+ # Longer, multiple paragraph explanation.
11
+ description: |
12
+ There is a lot to say about my little project.
13
+
14
+ But I am not saying any of it right now.
15
+
16
+
17
+ # Who made this
18
+ authors: ["a person with <an@email.address>"]
19
+
20
+ # The version of the Project
21
+ version: 1.56.12
22
+
23
+ routes:
24
+ include:
25
+ - custom_api.lua
26
+
27
+ formatversion: 1.0.0
@@ -0,0 +1,20 @@
1
+ {
2
+ "default_page": "index.html",
3
+ "file_dir": "public",
4
+ "custom_api": "sample_api.lua",
5
+ "custom_api_hook": "_init",
6
+ "modules": {
7
+ "auth": "modules/util.lua",
8
+ "debug": "modules/debug.lua",
9
+ "listen": "modules/listen.lua"
10
+ },
11
+ "event_handler": {
12
+ "device": {
13
+ "datapoint": "event_handler/product.lua"
14
+ },
15
+ "timer": {
16
+ "timer": "event_handler/timer.lua"
17
+ }
18
+ },
19
+ "cors": {"origin": ["http://localhost:*"]}
20
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "default_page": "index.html",
3
+ "file_dir": "public",
4
+ "custom_api_hook": "_init",
5
+ "modules": {
6
+ "auth": "modules/util.lua",
7
+ "debug": "modules/debug.lua",
8
+ "listen": "modules/listen.lua"
9
+ },
10
+ "event_handler": {
11
+ "device": {
12
+ "datapoint": "event_handler/product.lua"
13
+ },
14
+ "timer": {
15
+ "timer": "event_handler/timer.lua"
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "default_page": "index.html",
3
+ "file_dir": "public",
4
+ "custom_api": "sample_api.lua",
5
+ "custom_api_hook": "_init",
6
+ "modules": {
7
+ "auth": "modules/util.lua",
8
+ "debug": "modules/debug.lua",
9
+ "listen": "modules/listen.lua"
10
+ },
11
+ "event_handler": {
12
+ "device": {
13
+ "datapoint": "event_handler/product.lua"
14
+ },
15
+ "timer": {
16
+ "timer": "event_handler/timer.lua"
17
+ }
18
+ },
19
+ "cors": {"origin": ["http://localhost:*"]},
20
+ "version": "0.2"
21
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "default_page": "index.html",
3
+ "assets": "public",
4
+ "routes": "sample_api.lua",
5
+ "modules": {
6
+ "auth": "modules/util.lua",
7
+ "debug": "modules/debug.lua",
8
+ "listen": "modules/listen.lua"
9
+ },
10
+ "services": {
11
+ "device": {
12
+ "datapoint": "event_handler/product.lua"
13
+ },
14
+ "timer": {
15
+ "timer": "event_handler/timer.lua"
16
+ }
17
+ },
18
+ "cors": {"origin": ["http://localhost:*"]},
19
+ "version": "0.3.0"
20
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "default_page": "index.html",
3
+ "assets": "public",
4
+ "modules": {
5
+ "auth": "modules/util.lua",
6
+ "debug": "modules/debug.lua",
7
+ "listen": "modules/listen.lua"
8
+ },
9
+ "services": {
10
+ "device": {
11
+ "datapoint": "event_handler/product.lua"
12
+ },
13
+ "timer": {
14
+ "timer": "event_handler/timer.lua"
15
+ }
16
+ },
17
+ "cors": {"origin": ["http://localhost:*"]},
18
+ "version": "0.3.0"
19
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "default_page": "index.html",
3
+ "assets": "public",
4
+ "routes": "sample_api.lua",
5
+ "modules": {
6
+ "auth": "modules/util.lua",
7
+ "debug": "modules/debug.lua",
8
+ "listen": "modules/listen.lua"
9
+ },
10
+ "services": {
11
+ "device": {
12
+ "datapoint": "event_handler/product.lua"
13
+ },
14
+ "timer": {
15
+ "timer": "event_handler/timer.lua"
16
+ }
17
+ },
18
+ "cors": {"origin": ["http://localhost:*"]},
19
+ "version": "0.3"
20
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "default_page": "index.html",
3
+ "file_dir": "public",
4
+ "custom_api": "sample_api.lua",
5
+ "custom_api_hook": "_init",
6
+ "modules": {
7
+ "auth": "modules/util.lua",
8
+ "debug": "modules/debug.lua",
9
+ "listen": "modules/listen.lua"
10
+ },
11
+ "event_handler": {
12
+ "device": {
13
+ "datapoint": "event_handler/product.lua"
14
+ },
15
+ "timer": {
16
+ "timer": "event_handler/timer.lua"
17
+ }
18
+ },
19
+ "cors": {"origin": ["http://localhost:*"]}
20
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "email": "test@user.account",
3
+ "password": "gibblygook",
4
+ "solution_id": "ABCDEFG",
5
+ "product_id": "HIJKLMNOP"
6
+ }
@@ -0,0 +1,9 @@
1
+ [solution]
2
+ id = XXXXXXXXXX
3
+
4
+ [test]
5
+ bob = build
6
+
7
+ [s-fDEADBEEFGAEG]
8
+ spec = bobo.yaml
9
+
@@ -0,0 +1,42 @@
1
+ [tool]
2
+ verbose = false
3
+ debug = false
4
+ dry = false
5
+ fullerror = false
6
+ outformat = best
7
+
8
+ [net]
9
+ host = bizapi.hosted.exosite.io
10
+
11
+ [location]
12
+ base = <%= File.realpath(@projectDir) %>
13
+ files = files
14
+ endpoints = routes
15
+ modules = modules
16
+ eventhandlers = services
17
+ specs = specs/resources.yaml
18
+ cors = cors.yaml
19
+
20
+ [sync]
21
+ bydefault = files
22
+
23
+ [files]
24
+ default_page = index.html
25
+ searchFor = **/*
26
+ ignoring =
27
+
28
+ [endpoints]
29
+ searchFor = {,../endpoints}/*.lua {,../endpoints}s/*/*.lua
30
+ ignoring = *_test.lua *_spec.lua .*
31
+
32
+ [eventhandler]
33
+ searchFor = *.lua */*.lua {../eventhandlers,../event_handler}/*.lua {../eventhandlers,../event_handler}/*/*.lua
34
+ ignoring = *_test.lua *_spec.lua .*
35
+ skiplist = websocket webservice device.service_call
36
+
37
+ [modules]
38
+ searchFor = *.lua */*.lua
39
+ ignoring = *_test.lua *_spec.lua .*
40
+
41
+ [diff]
42
+ cmd = <%= Gem.win_platform? ? 'fc' : 'diff -u' %>
@@ -0,0 +1,8 @@
1
+ [solution]
2
+ id = XXXXXXXXXX
3
+
4
+ [doThisTest]
5
+
6
+ [s-fDEADBEEFGAEG]
7
+ spec = bobo.yaml
8
+
@@ -0,0 +1,3 @@
1
+ [tool]
2
+ bob = build
3
+
@@ -0,0 +1,116 @@
1
+
2
+ # Example client specification file
3
+ # Specification files are in YAML format (a superset of JSON
4
+ # with more readable syntax and support for comments) and
5
+ # look like this. They may contain comments that begin
6
+ # with a # sign.
7
+
8
+ # Device client model information
9
+ device:
10
+ model: "myModel"
11
+ vendor: "myVendor"
12
+
13
+ # list of dataports that must exist
14
+ dataports:
15
+ # this the absolute minimum needed to specify a
16
+ # dataport.
17
+ - alias: mystring
18
+ # names are created, but not compared
19
+ - name: Temperature
20
+ # aliases, type, and format are created
21
+ # and compared
22
+ alias: temp
23
+ format: float
24
+ unit: °F
25
+ - name: LED Control
26
+ alias: led6
27
+ format: integer
28
+ - alias: config
29
+ # format should be string, and parseable JSON
30
+ format: string/json
31
+ # initial value (if no other value is read back)
32
+ initial: '{"text": "555-555-1234", "email": "jeff@555.com"}'
33
+ - alias: person
34
+ format: string/json
35
+ # JSON schema specified inline (http://json-schema.org/)
36
+ # format must be string/json to do validate
37
+ # you may also specify a string to reference schema in an
38
+ # external file. E.g. jsonschema: personschema.json
39
+ jsonschema: {"title": "Person Schema",
40
+ "type": "object",
41
+ "properties": {"name": {"type": "string"}},
42
+ "required": ["name"]}
43
+ initial: '{"name":"John Doe"}'
44
+ - alias: place
45
+ # An description of the dataport.
46
+ description: 'This is a place I have been'
47
+ # Dataports are not public by default,
48
+ # but if you want to share one with the world
49
+ public: true
50
+
51
+ # any dataports not listed but found in the client
52
+ # are ignored. The spec command does not delete things.
53
+
54
+ # list of script datarules that must exist
55
+ scripts:
56
+ # by default, scripts are datarules with
57
+ # names and aliases set to the file name
58
+ - file: test/files/helloworld.lua
59
+ # you can also set them explicitly
60
+ - file: test/files/helloworld.lua
61
+ alias: greeting
62
+ # you can also place lua code inline
63
+ - alias: singleLineScript
64
+ code: debug('hello from inside lua!')
65
+ # multiline lua scripts should start with | and
66
+ # be indented inside the "code:" key.
67
+ - alias: multilineScript
68
+ code: |
69
+ for x=1,10 do
70
+ debug('hello from for loop ' .. x)
71
+ end
72
+ # simple templating for script aliases and
73
+ # content is also supported.
74
+ - file: test/files/convert.lua
75
+ # if <% id %> is embedded in aliases
76
+ # or script content, the --ids parameter must
77
+ # be passed in. The spec command then expects
78
+ # a script or dataport resource per id passed, substituting
79
+ # each ID for <% id %>. In this example, if the command was:
80
+ #
81
+ # $ exo spec mysensor sensorspec.yaml --ids=A,B
82
+ #
83
+ # ...then the spec command looks for *two* script datarules
84
+ # in mysensor, with aliases convertA.lua and convertB.lua.
85
+ # Additionally, any instances of <% id %> in the content of
86
+ # convert.lua are substituted with A and B before being
87
+ # written to each script datarule.
88
+ #
89
+ alias: convert<% id %>.lua
90
+
91
+ # list of dispatches that must exist
92
+ dispatches:
93
+ - alias: myDispatch
94
+ # email | http_get | http_post | http_put | sms | xmpp
95
+ method: email
96
+ recipient: support@exosite.com
97
+ message: hello from Exoline spec example!
98
+ subject: hello!
99
+ # may be an RID or alias
100
+ subscribe: mystring
101
+
102
+ # list of simple datarules that must exist.
103
+ # scripts may go here too, but it's better to
104
+ # to put them under scripts (above)
105
+ datarules:
106
+ - alias: highTemp
107
+ format: float
108
+ subscribe: temp
109
+ rule: {
110
+ "simple": {
111
+ "comparison": "gt",
112
+ "constant": 80,
113
+ "repeat": true
114
+ }
115
+ }
116
+