chef-zero 15.0.11 → 15.0.21
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.
- checksums.yaml +4 -4
- data/Gemfile +36 -29
- data/LICENSE +201 -201
- data/Rakefile +73 -68
- data/bin/chef-zero +111 -111
- data/chef-zero.gemspec +34 -28
- data/lib/chef_zero/chef_data/acl_path.rb +140 -140
- data/lib/chef_zero/chef_data/cookbook_data.rb +237 -237
- data/lib/chef_zero/chef_data/data_normalizer.rb +276 -276
- data/lib/chef_zero/chef_data/default_creator.rb +476 -476
- data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -29
- data/lib/chef_zero/data_store/data_error.rb +32 -32
- data/lib/chef_zero/data_store/data_not_found_error.rb +29 -29
- data/lib/chef_zero/data_store/default_facade.rb +143 -147
- data/lib/chef_zero/data_store/interface_v1.rb +67 -67
- data/lib/chef_zero/data_store/interface_v2.rb +18 -18
- data/lib/chef_zero/data_store/memory_store.rb +33 -33
- data/lib/chef_zero/data_store/memory_store_v2.rb +159 -159
- data/lib/chef_zero/data_store/raw_file_store.rb +143 -143
- data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +150 -150
- data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +105 -105
- data/lib/chef_zero/dist.rb +9 -9
- data/lib/chef_zero/endpoints/acl_endpoint.rb +39 -39
- data/lib/chef_zero/endpoints/acls_endpoint.rb +41 -41
- data/lib/chef_zero/endpoints/actor_default_key_endpoint.rb +78 -78
- data/lib/chef_zero/endpoints/actor_endpoint.rb +184 -184
- data/lib/chef_zero/endpoints/actor_key_endpoint.rb +62 -62
- data/lib/chef_zero/endpoints/actor_keys_endpoint.rb +129 -129
- data/lib/chef_zero/endpoints/actors_endpoint.rb +104 -104
- data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +32 -32
- data/lib/chef_zero/endpoints/container_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/containers_endpoint.rb +25 -25
- data/lib/chef_zero/endpoints/controls_endpoint.rb +16 -16
- data/lib/chef_zero/endpoints/cookbook_artifact_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/cookbook_artifact_identifier_endpoint.rb +68 -68
- data/lib/chef_zero/endpoints/cookbook_artifacts_endpoint.rb +34 -34
- data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -39
- data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +136 -136
- data/lib/chef_zero/endpoints/cookbooks_base.rb +80 -80
- data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +19 -19
- data/lib/chef_zero/endpoints/data_bag_endpoint.rb +45 -45
- data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -25
- data/lib/chef_zero/endpoints/data_bags_endpoint.rb +23 -23
- data/lib/chef_zero/endpoints/dummy_endpoint.rb +29 -29
- data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +126 -126
- data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -33
- data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -23
- data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/environment_role_endpoint.rb +36 -36
- data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/group_endpoint.rb +20 -20
- data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -13
- data/lib/chef_zero/endpoints/license_endpoint.rb +25 -25
- data/lib/chef_zero/endpoints/node_endpoint.rb +34 -34
- data/lib/chef_zero/endpoints/node_identifiers_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/nodes_endpoint.rb +34 -34
- data/lib/chef_zero/endpoints/not_found_endpoint.rb +11 -11
- data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +30 -30
- data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/organization_endpoint.rb +47 -47
- data/lib/chef_zero/endpoints/organization_user_base.rb +15 -15
- data/lib/chef_zero/endpoints/organization_user_default_key_endpoint.rb +16 -16
- data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/organization_user_key_endpoint.rb +17 -17
- data/lib/chef_zero/endpoints/organization_user_keys_endpoint.rb +17 -17
- data/lib/chef_zero/endpoints/organization_users_endpoint.rb +43 -43
- data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -20
- data/lib/chef_zero/endpoints/organizations_endpoint.rb +61 -61
- data/lib/chef_zero/endpoints/policies_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/policy_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/policy_group_endpoint.rb +46 -46
- data/lib/chef_zero/endpoints/policy_group_policy_endpoint.rb +83 -83
- data/lib/chef_zero/endpoints/policy_groups_endpoint.rb +38 -38
- data/lib/chef_zero/endpoints/policy_revision_endpoint.rb +66 -66
- data/lib/chef_zero/endpoints/policy_revisions_endpoint.rb +15 -15
- data/lib/chef_zero/endpoints/principal_endpoint.rb +55 -55
- data/lib/chef_zero/endpoints/rest_list_endpoint.rb +42 -42
- data/lib/chef_zero/endpoints/rest_object_endpoint.rb +78 -78
- data/lib/chef_zero/endpoints/role_endpoint.rb +16 -16
- data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -14
- data/lib/chef_zero/endpoints/sandbox_endpoint.rb +27 -27
- data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +51 -50
- data/lib/chef_zero/endpoints/search_endpoint.rb +208 -208
- data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -18
- data/lib/chef_zero/endpoints/server_api_version_endpoint.rb +14 -14
- data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -30
- data/lib/chef_zero/endpoints/universe_endpoint.rb +15 -15
- data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +41 -41
- data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -19
- data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -19
- data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/version_endpoint.rb +13 -13
- data/lib/chef_zero/log.rb +7 -7
- data/lib/chef_zero/rest_base.rb +332 -332
- data/lib/chef_zero/rest_error_response.rb +11 -11
- data/lib/chef_zero/rest_request.rb +84 -88
- data/lib/chef_zero/rest_router.rb +72 -72
- data/lib/chef_zero/rspec.rb +355 -355
- data/lib/chef_zero/server.rb +730 -729
- data/lib/chef_zero/socketless_server_map.rb +92 -93
- data/lib/chef_zero/solr/query/binary_operator.rb +52 -52
- data/lib/chef_zero/solr/query/phrase.rb +23 -23
- data/lib/chef_zero/solr/query/range_query.rb +46 -46
- data/lib/chef_zero/solr/query/regexpable_query.rb +30 -30
- data/lib/chef_zero/solr/query/subquery.rb +37 -37
- data/lib/chef_zero/solr/query/term.rb +45 -45
- data/lib/chef_zero/solr/query/unary_operator.rb +41 -41
- data/lib/chef_zero/solr/solr_doc.rb +53 -53
- data/lib/chef_zero/solr/solr_parser.rb +208 -208
- data/lib/chef_zero/version.rb +3 -3
- data/lib/chef_zero.rb +10 -10
- data/spec/run_oc_pedant.rb +226 -226
- data/spec/search_spec.rb +36 -36
- data/spec/server_spec.rb +96 -96
- data/spec/socketless_server_map_spec.rb +74 -74
- data/spec/support/oc_pedant.rb +149 -149
- data/spec/support/secrets.json +6 -6
- data/spec/support/stickywicket.pem +27 -27
- metadata +72 -15
@@ -1,41 +1,41 @@
|
|
1
|
-
module ChefZero
|
2
|
-
module Solr
|
3
|
-
module Query
|
4
|
-
class UnaryOperator
|
5
|
-
def initialize(operator, operand)
|
6
|
-
@operator = operator
|
7
|
-
@operand = operand
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_s
|
11
|
-
"#{operator} #{operand}"
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_reader :operator
|
15
|
-
attr_reader :operand
|
16
|
-
|
17
|
-
def matches_doc?(doc)
|
18
|
-
case @operator
|
19
|
-
when "-", "NOT", "!"
|
20
|
-
!operand.matches_doc?(doc)
|
21
|
-
when "+"
|
22
|
-
# TODO This operator uses relevance to eliminate other, unrelated
|
23
|
-
# expressions. +a OR b means "if it has b but not a, don't return it"
|
24
|
-
raise "+ not supported yet, because it is hard."
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def matches_values?(values)
|
29
|
-
case @operator
|
30
|
-
when "-", "NOT", "!"
|
31
|
-
!operand.matches_values?(values)
|
32
|
-
when "+"
|
33
|
-
# TODO This operator uses relevance to eliminate other, unrelated
|
34
|
-
# expressions. +a OR b means "if it has b but not a, don't return it"
|
35
|
-
raise "+ not supported yet, because it is hard."
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
1
|
+
module ChefZero
|
2
|
+
module Solr
|
3
|
+
module Query
|
4
|
+
class UnaryOperator
|
5
|
+
def initialize(operator, operand)
|
6
|
+
@operator = operator
|
7
|
+
@operand = operand
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"#{operator} #{operand}"
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :operator
|
15
|
+
attr_reader :operand
|
16
|
+
|
17
|
+
def matches_doc?(doc)
|
18
|
+
case @operator
|
19
|
+
when "-", "NOT", "!"
|
20
|
+
!operand.matches_doc?(doc)
|
21
|
+
when "+"
|
22
|
+
# TODO This operator uses relevance to eliminate other, unrelated
|
23
|
+
# expressions. +a OR b means "if it has b but not a, don't return it"
|
24
|
+
raise "+ not supported yet, because it is hard."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def matches_values?(values)
|
29
|
+
case @operator
|
30
|
+
when "-", "NOT", "!"
|
31
|
+
!operand.matches_values?(values)
|
32
|
+
when "+"
|
33
|
+
# TODO This operator uses relevance to eliminate other, unrelated
|
34
|
+
# expressions. +a OR b means "if it has b but not a, don't return it"
|
35
|
+
raise "+ not supported yet, because it is hard."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,53 +1,53 @@
|
|
1
|
-
module ChefZero
|
2
|
-
module Solr
|
3
|
-
# This does what expander does, flattening the json doc into keys and values
|
4
|
-
# so that solr can search them.
|
5
|
-
class SolrDoc
|
6
|
-
def initialize(json, id)
|
7
|
-
@json = json
|
8
|
-
@id = id
|
9
|
-
end
|
10
|
-
|
11
|
-
def [](key)
|
12
|
-
matching_values { |match_key| match_key == key }
|
13
|
-
end
|
14
|
-
|
15
|
-
def matching_values(&block)
|
16
|
-
result = []
|
17
|
-
key_values(nil, @json) do |key, value|
|
18
|
-
if yield(key)
|
19
|
-
result << value.to_s
|
20
|
-
end
|
21
|
-
end
|
22
|
-
# Handle manufactured value(s)
|
23
|
-
if yield("X_CHEF_id_CHEF_X")
|
24
|
-
result << @id.to_s
|
25
|
-
end
|
26
|
-
|
27
|
-
result.uniq
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def key_values(key_so_far, value, &block)
|
33
|
-
if value.is_a?(Hash)
|
34
|
-
value.each_pair do |child_key, child_value|
|
35
|
-
yield(child_key, child_value.to_s)
|
36
|
-
if key_so_far
|
37
|
-
new_key = "#{key_so_far}_#{child_key}"
|
38
|
-
key_values(new_key, child_value, &block)
|
39
|
-
else
|
40
|
-
key_values(child_key, child_value, &block) if child_value.is_a?(Hash) || child_value.is_a?(Array)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
elsif value.is_a?(Array)
|
44
|
-
value.each do |child_value|
|
45
|
-
key_values(key_so_far, child_value, &block)
|
46
|
-
end
|
47
|
-
else
|
48
|
-
yield(key_so_far || "text", value.to_s)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
1
|
+
module ChefZero
|
2
|
+
module Solr
|
3
|
+
# This does what expander does, flattening the json doc into keys and values
|
4
|
+
# so that solr can search them.
|
5
|
+
class SolrDoc
|
6
|
+
def initialize(json, id)
|
7
|
+
@json = json
|
8
|
+
@id = id
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](key)
|
12
|
+
matching_values { |match_key| match_key == key }
|
13
|
+
end
|
14
|
+
|
15
|
+
def matching_values(&block)
|
16
|
+
result = []
|
17
|
+
key_values(nil, @json) do |key, value|
|
18
|
+
if yield(key)
|
19
|
+
result << value.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
# Handle manufactured value(s)
|
23
|
+
if yield("X_CHEF_id_CHEF_X")
|
24
|
+
result << @id.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
result.uniq
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def key_values(key_so_far, value, &block)
|
33
|
+
if value.is_a?(Hash)
|
34
|
+
value.each_pair do |child_key, child_value|
|
35
|
+
yield(child_key, child_value.to_s)
|
36
|
+
if key_so_far
|
37
|
+
new_key = "#{key_so_far}_#{child_key}"
|
38
|
+
key_values(new_key, child_value, &block)
|
39
|
+
else
|
40
|
+
key_values(child_key, child_value, &block) if child_value.is_a?(Hash) || child_value.is_a?(Array)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
elsif value.is_a?(Array)
|
44
|
+
value.each do |child_value|
|
45
|
+
key_values(key_so_far, child_value, &block)
|
46
|
+
end
|
47
|
+
else
|
48
|
+
yield(key_so_far || "text", value.to_s)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -1,208 +1,208 @@
|
|
1
|
-
require_relative "query/binary_operator"
|
2
|
-
require_relative "query/unary_operator"
|
3
|
-
require_relative "query/term"
|
4
|
-
require_relative "query/phrase"
|
5
|
-
require_relative "query/range_query"
|
6
|
-
require_relative "query/subquery"
|
7
|
-
|
8
|
-
module ChefZero
|
9
|
-
module Solr
|
10
|
-
class ParseError < RuntimeError; end
|
11
|
-
|
12
|
-
class SolrParser
|
13
|
-
def initialize(query_string)
|
14
|
-
@query_string = query_string
|
15
|
-
@index = 0
|
16
|
-
end
|
17
|
-
|
18
|
-
def parse
|
19
|
-
read_expression
|
20
|
-
end
|
21
|
-
|
22
|
-
#
|
23
|
-
# Tokenization
|
24
|
-
#
|
25
|
-
def peek_token
|
26
|
-
@next_token ||= parse_token
|
27
|
-
end
|
28
|
-
|
29
|
-
def next_token
|
30
|
-
result = peek_token
|
31
|
-
@next_token = nil
|
32
|
-
result
|
33
|
-
end
|
34
|
-
|
35
|
-
def parse_token
|
36
|
-
# Skip whitespace
|
37
|
-
skip_whitespace
|
38
|
-
return nil if eof?
|
39
|
-
|
40
|
-
# Operators
|
41
|
-
operator = peek_operator_token
|
42
|
-
if operator
|
43
|
-
@index += operator.length
|
44
|
-
operator
|
45
|
-
else
|
46
|
-
# Everything that isn't whitespace or an operator, is part of a term
|
47
|
-
# (characters plus backslashed escaped characters)
|
48
|
-
start_index = @index
|
49
|
-
loop do
|
50
|
-
if @query_string[@index] ==
|
51
|
-
@index += 1
|
52
|
-
end
|
53
|
-
@index += 1 unless eof?
|
54
|
-
break if eof? || !peek_term_token
|
55
|
-
end
|
56
|
-
@query_string[start_index..@index - 1]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def skip_whitespace
|
61
|
-
if @query_string[@index] =~ /\s/
|
62
|
-
whitespace = /\s+/.match(@query_string, @index) || peek
|
63
|
-
@index += whitespace[0].length
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def peek_term_token
|
68
|
-
return nil if @query_string[@index] =~ /\s/
|
69
|
-
|
70
|
-
op = peek_operator_token
|
71
|
-
!op || op == "-"
|
72
|
-
end
|
73
|
-
|
74
|
-
def peek_operator_token
|
75
|
-
if ['"', "+", "-", "!", "(", ")", "{", "}", "[", "]", "^", ":"].include?(@query_string[@index])
|
76
|
-
return @query_string[@index]
|
77
|
-
else
|
78
|
-
result = @query_string[@index..@index + 1]
|
79
|
-
if ["&&", "||"].include?(result)
|
80
|
-
return result
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
nil
|
85
|
-
end
|
86
|
-
|
87
|
-
def eof?
|
88
|
-
!@next_token && @index >= @query_string.length
|
89
|
-
end
|
90
|
-
|
91
|
-
# Parse tree creation
|
92
|
-
def read_expression
|
93
|
-
result = read_single_expression
|
94
|
-
# Expression is over when we hit a close paren or eof
|
95
|
-
# (peek_token has the side effect of skipping whitespace for us, so we
|
96
|
-
# really know if we're at eof or not)
|
97
|
-
until peek_token == ")" || eof?
|
98
|
-
operator = peek_token
|
99
|
-
if binary_operator?(operator)
|
100
|
-
next_token
|
101
|
-
else
|
102
|
-
# If 2 terms are next to each other, the default operator is OR
|
103
|
-
operator = "OR"
|
104
|
-
end
|
105
|
-
next_expression = read_single_expression
|
106
|
-
|
107
|
-
# Build the operator, taking precedence into account
|
108
|
-
if result.is_a?(Query::BinaryOperator) &&
|
109
|
-
binary_operator_precedence(operator) > binary_operator_precedence(result.operator)
|
110
|
-
# a+b*c -> a+(b*c)
|
111
|
-
new_right = Query::BinaryOperator.new(result.right, operator, next_expression)
|
112
|
-
result = Query::BinaryOperator.new(result.left, result.operator, new_right)
|
113
|
-
else
|
114
|
-
# a*b+c -> (a*b)+c
|
115
|
-
result = Query::BinaryOperator.new(result, operator, next_expression)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
result
|
119
|
-
end
|
120
|
-
|
121
|
-
def parse_error(token, str)
|
122
|
-
raise ChefZero::Solr::ParseError, "Error on token '#{token}' at #{@index} of '#{@query_string}': #{str}"
|
123
|
-
end
|
124
|
-
|
125
|
-
def read_single_expression
|
126
|
-
token = next_token
|
127
|
-
# If EOF, we have a problem Houston
|
128
|
-
if !token
|
129
|
-
parse_error(nil, "Expected expression!")
|
130
|
-
|
131
|
-
# If it's an unary operand, build that
|
132
|
-
elsif unary_operator?(token)
|
133
|
-
operand = read_single_expression
|
134
|
-
# TODO We rely on all unary operators having higher precedence than all
|
135
|
-
# binary operators. Check if this is the case.
|
136
|
-
Query::UnaryOperator.new(token, operand)
|
137
|
-
|
138
|
-
# If it's the start of a phrase, read the terms in the phrase
|
139
|
-
elsif token == '"'
|
140
|
-
# Read terms until close "
|
141
|
-
phrase_terms = []
|
142
|
-
until (term = next_token) == '"'
|
143
|
-
phrase_terms << Query::Term.new(term)
|
144
|
-
end
|
145
|
-
Query::Phrase.new(phrase_terms)
|
146
|
-
|
147
|
-
# If it's the start of a range query, build that
|
148
|
-
elsif token == "{" || token == "["
|
149
|
-
left = next_token
|
150
|
-
parse_error(left, "Expected left term in range query") unless left
|
151
|
-
to = next_token
|
152
|
-
parse_error(left, "Expected TO in range query") if to != "TO"
|
153
|
-
right = next_token
|
154
|
-
parse_error(right, "Expected left term in range query") unless right
|
155
|
-
end_range = next_token
|
156
|
-
parse_error(right, "Expected end range '#{end_range}") unless ["}", "]"].include?(end_range)
|
157
|
-
Query::RangeQuery.new(left, right, token == "[", end_range == "]")
|
158
|
-
|
159
|
-
elsif token == "("
|
160
|
-
subquery = read_expression
|
161
|
-
close_paren = next_token
|
162
|
-
parse_error(close_paren, "Expected ')'") if close_paren != ")"
|
163
|
-
Query::Subquery.new(subquery)
|
164
|
-
|
165
|
-
# If it's the end of a closure, raise an exception
|
166
|
-
elsif ["}", "]", ")"].include?(token)
|
167
|
-
parse_error(token, "Unexpected end paren")
|
168
|
-
|
169
|
-
# If it's a binary operator, raise an exception
|
170
|
-
elsif binary_operator?(token)
|
171
|
-
parse_error(token, "Unexpected binary operator")
|
172
|
-
|
173
|
-
# Otherwise it's a term.
|
174
|
-
else
|
175
|
-
term = Query::Term.new(token)
|
176
|
-
if peek_token == ":"
|
177
|
-
Query::BinaryOperator.new(term, next_token, read_single_expression)
|
178
|
-
else
|
179
|
-
term
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
def unary_operator?(token)
|
185
|
-
[ "NOT", "+", "-", "!" ].include?(token)
|
186
|
-
end
|
187
|
-
|
188
|
-
def binary_operator?(token)
|
189
|
-
[ "AND", "OR", "^", ":"].include?(token)
|
190
|
-
end
|
191
|
-
|
192
|
-
def binary_operator_precedence(token)
|
193
|
-
case token
|
194
|
-
when "^"
|
195
|
-
4
|
196
|
-
when ":"
|
197
|
-
3
|
198
|
-
when "AND"
|
199
|
-
2
|
200
|
-
when "OR"
|
201
|
-
1
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
DEFAULT_FIELD = "text".freeze
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
1
|
+
require_relative "query/binary_operator"
|
2
|
+
require_relative "query/unary_operator"
|
3
|
+
require_relative "query/term"
|
4
|
+
require_relative "query/phrase"
|
5
|
+
require_relative "query/range_query"
|
6
|
+
require_relative "query/subquery"
|
7
|
+
|
8
|
+
module ChefZero
|
9
|
+
module Solr
|
10
|
+
class ParseError < RuntimeError; end
|
11
|
+
|
12
|
+
class SolrParser
|
13
|
+
def initialize(query_string)
|
14
|
+
@query_string = query_string
|
15
|
+
@index = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse
|
19
|
+
read_expression
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Tokenization
|
24
|
+
#
|
25
|
+
def peek_token
|
26
|
+
@next_token ||= parse_token
|
27
|
+
end
|
28
|
+
|
29
|
+
def next_token
|
30
|
+
result = peek_token
|
31
|
+
@next_token = nil
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_token
|
36
|
+
# Skip whitespace
|
37
|
+
skip_whitespace
|
38
|
+
return nil if eof?
|
39
|
+
|
40
|
+
# Operators
|
41
|
+
operator = peek_operator_token
|
42
|
+
if operator
|
43
|
+
@index += operator.length
|
44
|
+
operator
|
45
|
+
else
|
46
|
+
# Everything that isn't whitespace or an operator, is part of a term
|
47
|
+
# (characters plus backslashed escaped characters)
|
48
|
+
start_index = @index
|
49
|
+
loop do
|
50
|
+
if @query_string[@index] == "\\"
|
51
|
+
@index += 1
|
52
|
+
end
|
53
|
+
@index += 1 unless eof?
|
54
|
+
break if eof? || !peek_term_token
|
55
|
+
end
|
56
|
+
@query_string[start_index..@index - 1]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def skip_whitespace
|
61
|
+
if @query_string[@index] =~ /\s/
|
62
|
+
whitespace = /\s+/.match(@query_string, @index) || peek
|
63
|
+
@index += whitespace[0].length
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def peek_term_token
|
68
|
+
return nil if @query_string[@index] =~ /\s/
|
69
|
+
|
70
|
+
op = peek_operator_token
|
71
|
+
!op || op == "-"
|
72
|
+
end
|
73
|
+
|
74
|
+
def peek_operator_token
|
75
|
+
if ['"', "+", "-", "!", "(", ")", "{", "}", "[", "]", "^", ":"].include?(@query_string[@index])
|
76
|
+
return @query_string[@index]
|
77
|
+
else
|
78
|
+
result = @query_string[@index..@index + 1]
|
79
|
+
if ["&&", "||"].include?(result)
|
80
|
+
return result
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def eof?
|
88
|
+
!@next_token && @index >= @query_string.length
|
89
|
+
end
|
90
|
+
|
91
|
+
# Parse tree creation
|
92
|
+
def read_expression
|
93
|
+
result = read_single_expression
|
94
|
+
# Expression is over when we hit a close paren or eof
|
95
|
+
# (peek_token has the side effect of skipping whitespace for us, so we
|
96
|
+
# really know if we're at eof or not)
|
97
|
+
until peek_token == ")" || eof?
|
98
|
+
operator = peek_token
|
99
|
+
if binary_operator?(operator)
|
100
|
+
next_token
|
101
|
+
else
|
102
|
+
# If 2 terms are next to each other, the default operator is OR
|
103
|
+
operator = "OR"
|
104
|
+
end
|
105
|
+
next_expression = read_single_expression
|
106
|
+
|
107
|
+
# Build the operator, taking precedence into account
|
108
|
+
if result.is_a?(Query::BinaryOperator) &&
|
109
|
+
binary_operator_precedence(operator) > binary_operator_precedence(result.operator)
|
110
|
+
# a+b*c -> a+(b*c)
|
111
|
+
new_right = Query::BinaryOperator.new(result.right, operator, next_expression)
|
112
|
+
result = Query::BinaryOperator.new(result.left, result.operator, new_right)
|
113
|
+
else
|
114
|
+
# a*b+c -> (a*b)+c
|
115
|
+
result = Query::BinaryOperator.new(result, operator, next_expression)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
result
|
119
|
+
end
|
120
|
+
|
121
|
+
def parse_error(token, str)
|
122
|
+
raise ChefZero::Solr::ParseError, "Error on token '#{token}' at #{@index} of '#{@query_string}': #{str}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def read_single_expression
|
126
|
+
token = next_token
|
127
|
+
# If EOF, we have a problem Houston
|
128
|
+
if !token
|
129
|
+
parse_error(nil, "Expected expression!")
|
130
|
+
|
131
|
+
# If it's an unary operand, build that
|
132
|
+
elsif unary_operator?(token)
|
133
|
+
operand = read_single_expression
|
134
|
+
# TODO We rely on all unary operators having higher precedence than all
|
135
|
+
# binary operators. Check if this is the case.
|
136
|
+
Query::UnaryOperator.new(token, operand)
|
137
|
+
|
138
|
+
# If it's the start of a phrase, read the terms in the phrase
|
139
|
+
elsif token == '"'
|
140
|
+
# Read terms until close "
|
141
|
+
phrase_terms = []
|
142
|
+
until (term = next_token) == '"'
|
143
|
+
phrase_terms << Query::Term.new(term)
|
144
|
+
end
|
145
|
+
Query::Phrase.new(phrase_terms)
|
146
|
+
|
147
|
+
# If it's the start of a range query, build that
|
148
|
+
elsif token == "{" || token == "["
|
149
|
+
left = next_token
|
150
|
+
parse_error(left, "Expected left term in range query") unless left
|
151
|
+
to = next_token
|
152
|
+
parse_error(left, "Expected TO in range query") if to != "TO"
|
153
|
+
right = next_token
|
154
|
+
parse_error(right, "Expected left term in range query") unless right
|
155
|
+
end_range = next_token
|
156
|
+
parse_error(right, "Expected end range '#{end_range}") unless ["}", "]"].include?(end_range)
|
157
|
+
Query::RangeQuery.new(left, right, token == "[", end_range == "]")
|
158
|
+
|
159
|
+
elsif token == "("
|
160
|
+
subquery = read_expression
|
161
|
+
close_paren = next_token
|
162
|
+
parse_error(close_paren, "Expected ')'") if close_paren != ")"
|
163
|
+
Query::Subquery.new(subquery)
|
164
|
+
|
165
|
+
# If it's the end of a closure, raise an exception
|
166
|
+
elsif ["}", "]", ")"].include?(token)
|
167
|
+
parse_error(token, "Unexpected end paren")
|
168
|
+
|
169
|
+
# If it's a binary operator, raise an exception
|
170
|
+
elsif binary_operator?(token)
|
171
|
+
parse_error(token, "Unexpected binary operator")
|
172
|
+
|
173
|
+
# Otherwise it's a term.
|
174
|
+
else
|
175
|
+
term = Query::Term.new(token)
|
176
|
+
if peek_token == ":"
|
177
|
+
Query::BinaryOperator.new(term, next_token, read_single_expression)
|
178
|
+
else
|
179
|
+
term
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def unary_operator?(token)
|
185
|
+
[ "NOT", "+", "-", "!" ].include?(token)
|
186
|
+
end
|
187
|
+
|
188
|
+
def binary_operator?(token)
|
189
|
+
[ "AND", "OR", "^", ":"].include?(token)
|
190
|
+
end
|
191
|
+
|
192
|
+
def binary_operator_precedence(token)
|
193
|
+
case token
|
194
|
+
when "^"
|
195
|
+
4
|
196
|
+
when ":"
|
197
|
+
3
|
198
|
+
when "AND"
|
199
|
+
2
|
200
|
+
when "OR"
|
201
|
+
1
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
DEFAULT_FIELD = "text".freeze
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
data/lib/chef_zero/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module ChefZero
|
2
|
-
VERSION = "15.0.
|
3
|
-
end
|
1
|
+
module ChefZero
|
2
|
+
VERSION = "15.0.21".freeze
|
3
|
+
end
|
data/lib/chef_zero.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
module ChefZero
|
2
|
-
require_relative "chef_zero/log"
|
3
|
-
|
4
|
-
MIN_API_VERSION = 0
|
5
|
-
MAX_API_VERSION = 2
|
6
|
-
|
7
|
-
CERTIFICATE = "-----BEGIN CERTIFICATE-----\nMIIDMzCCApygAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMCVVMx\nEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFjAUBgNVBAoM\nDU9wc2NvZGUsIEluYy4xHDAaBgNVBAsME0NlcnRpZmljYXRlIFNlcnZpY2UxMjAw\nBgNVBAMMKW9wc2NvZGUuY29tL2VtYWlsQWRkcmVzcz1hdXRoQG9wc2NvZGUuY29t\nMB4XDTEyMTEyMTAwMzQyMVoXDTIyMTExOTAwMzQyMVowgZsxEDAOBgNVBAcTB1Nl\nYXR0bGUxEzARBgNVBAgTCldhc2hpbmd0b24xCzAJBgNVBAYTAlVTMRwwGgYDVQQL\nExNDZXJ0aWZpY2F0ZSBTZXJ2aWNlMRYwFAYDVQQKEw1PcHNjb2RlLCBJbmMuMS8w\nLQYDVQQDFCZVUkk6aHR0cDovL29wc2NvZGUuY29tL0dVSURTL3VzZXJfZ3VpZDCC\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANLDmPbR71bS2esZlZh/HfC6\n0azXFjl2677wq2ovk9xrUb0Ui4ZLC66TqQ9C/RBzOjXU4TRf3hgPTqvlCgHusl0d\nIcLCrsSl6kPEhJpYWWfRoroIAwf82A9yLQekhqXZEXu5EKkwoUMqyF6m0ZCasaE1\ny8niQxdLAsk3ady/CGQlFqHTPKFfU5UASR2LRtYC1MCIvJHDFRKAp9kPJbQo9P37\nZ8IU7cDudkZFgNLmDixlWsh7C0ghX8fgAlj1P6FgsFufygam973k79GhIP54dELB\nc0S6E8ekkRSOXU9jX/IoiXuFglBvFihAdhvED58bMXzj2AwXUyeAlxItnvs+NVUC\nAwEAATANBgkqhkiG9w0BAQUFAAOBgQBkFZRbMoywK3hb0/X7MXmPYa7nlfnd5UXq\nr2n32ettzZNmEPaI2d1j+//nL5qqhOlrWPS88eKEPnBOX/jZpUWOuAAddnrvFzgw\nrp/C2H7oMT+29F+5ezeViLKbzoFYb4yECHBoi66IFXNae13yj7taMboBeUmE664G\nTB/MZpRr8g==\n-----END CERTIFICATE-----\n".freeze
|
8
|
-
PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0sOY9tHvVtLZ6xmVmH8d\n8LrRrNcWOXbrvvCrai+T3GtRvRSLhksLrpOpD0L9EHM6NdThNF/eGA9Oq+UKAe6y\nXR0hwsKuxKXqQ8SEmlhZZ9GiuggDB/zYD3ItB6SGpdkRe7kQqTChQyrIXqbRkJqx\noTXLyeJDF0sCyTdp3L8IZCUWodM8oV9TlQBJHYtG1gLUwIi8kcMVEoCn2Q8ltCj0\n/ftnwhTtwO52RkWA0uYOLGVayHsLSCFfx+ACWPU/oWCwW5/KBqb3veTv0aEg/nh0\nQsFzRLoTx6SRFI5dT2Nf8iiJe4WCUG8WKEB2G8QPnxsxfOPYDBdTJ4CXEi2e+z41\nVQIDAQAB\n-----END PUBLIC KEY-----\n".freeze
|
9
|
-
PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA0sOY9tHvVtLZ6xmVmH8d8LrRrNcWOXbrvvCrai+T3GtRvRSL\nhksLrpOpD0L9EHM6NdThNF/eGA9Oq+UKAe6yXR0hwsKuxKXqQ8SEmlhZZ9GiuggD\nB/zYD3ItB6SGpdkRe7kQqTChQyrIXqbRkJqxoTXLyeJDF0sCyTdp3L8IZCUWodM8\noV9TlQBJHYtG1gLUwIi8kcMVEoCn2Q8ltCj0/ftnwhTtwO52RkWA0uYOLGVayHsL\nSCFfx+ACWPU/oWCwW5/KBqb3veTv0aEg/nh0QsFzRLoTx6SRFI5dT2Nf8iiJe4WC\nUG8WKEB2G8QPnxsxfOPYDBdTJ4CXEi2e+z41VQIDAQABAoIBAALhqbW2KQ+G0nPk\nZacwFbi01SkHx8YBWjfCEpXhEKRy0ytCnKW5YO+CFU2gHNWcva7+uhV9OgwaKXkw\nKHLeUJH1VADVqI4Htqw2g5mYm6BPvWnNsjzpuAp+BR+VoEGkNhj67r9hatMAQr0I\nitTvSH5rvd2EumYXIHKfz1K1SegUk1u1EL1RcMzRmZe4gDb6eNBs9Sg4im4ybTG6\npPIytA8vBQVWhjuAR2Tm+wZHiy0Az6Vu7c2mS07FSX6FO4E8SxWf8idaK9ijMGSq\nFvIS04mrY6XCPUPUC4qm1qNnhDPpOr7CpI2OO98SqGanStS5NFlSFXeXPpM280/u\nfZUA0AECgYEA+x7QUnffDrt7LK2cX6wbvn4mRnFxet7bJjrfWIHf+Rm0URikaNma\nh0/wNKpKBwIH+eHK/LslgzcplrqPytGGHLOG97Gyo5tGAzyLHUWBmsNkRksY2sPL\nuHq6pYWJNkqhnWGnIbmqCr0EWih82x/y4qxbJYpYqXMrit0wVf7yAgkCgYEA1twI\ngFaXqesetTPoEHSQSgC8S4D5/NkdriUXCYb06REcvo9IpFMuiOkVUYNN5d3MDNTP\nIdBicfmvfNELvBtXDomEUD8ls1UuoTIXRNGZ0VsZXu7OErXCK0JKNNyqRmOwcvYL\nJRqLfnlei5Ndo1lu286yL74c5rdTLs/nI2p4e+0CgYB079ZmcLeILrmfBoFI8+Y/\ngJLmPrFvXBOE6+lRV7kqUFPtZ6I3yQzyccETZTDvrnx0WjaiFavUPH27WMjY01S2\nTMtO0Iq1MPsbSrglO1as8MvjB9ldFcvp7gy4Q0Sv6XT0yqJ/S+vo8Df0m+H4UBpU\nf5o6EwBSd/UQxwtZIE0lsQKBgQCswfjX8Eg8KL/lJNpIOOE3j4XXE9ptksmJl2sB\njxDnQYoiMqVO808saHVquC/vTrpd6tKtNpehWwjeTFuqITWLi8jmmQ+gNTKsC9Gn\n1Pxf2Gb67PqnEpwQGln+TRtgQ5HBrdHiQIi+5am+gnw89pDrjjO5rZwhanAo6KPJ\n1zcPNQKBgQDxFu8v4frDmRNCVaZS4f1B6wTrcMrnibIDlnzrK9GG6Hz1U7dDv8s8\nNf4UmeMzDXjlPWZVOvS5+9HKJPdPj7/onv8B2m18+lcgTTDJBkza7R1mjL1Cje/Z\nKcVGsryKN6cjE7yCDasnA7R2rVBV/7NWeJV77bmzT5O//rW4yIfUIg==\n-----END RSA PRIVATE KEY-----\n".freeze
|
10
|
-
end
|
1
|
+
module ChefZero
|
2
|
+
require_relative "chef_zero/log"
|
3
|
+
|
4
|
+
MIN_API_VERSION = 0
|
5
|
+
MAX_API_VERSION = 2
|
6
|
+
|
7
|
+
CERTIFICATE = "-----BEGIN CERTIFICATE-----\nMIIDMzCCApygAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMCVVMx\nEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFjAUBgNVBAoM\nDU9wc2NvZGUsIEluYy4xHDAaBgNVBAsME0NlcnRpZmljYXRlIFNlcnZpY2UxMjAw\nBgNVBAMMKW9wc2NvZGUuY29tL2VtYWlsQWRkcmVzcz1hdXRoQG9wc2NvZGUuY29t\nMB4XDTEyMTEyMTAwMzQyMVoXDTIyMTExOTAwMzQyMVowgZsxEDAOBgNVBAcTB1Nl\nYXR0bGUxEzARBgNVBAgTCldhc2hpbmd0b24xCzAJBgNVBAYTAlVTMRwwGgYDVQQL\nExNDZXJ0aWZpY2F0ZSBTZXJ2aWNlMRYwFAYDVQQKEw1PcHNjb2RlLCBJbmMuMS8w\nLQYDVQQDFCZVUkk6aHR0cDovL29wc2NvZGUuY29tL0dVSURTL3VzZXJfZ3VpZDCC\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANLDmPbR71bS2esZlZh/HfC6\n0azXFjl2677wq2ovk9xrUb0Ui4ZLC66TqQ9C/RBzOjXU4TRf3hgPTqvlCgHusl0d\nIcLCrsSl6kPEhJpYWWfRoroIAwf82A9yLQekhqXZEXu5EKkwoUMqyF6m0ZCasaE1\ny8niQxdLAsk3ady/CGQlFqHTPKFfU5UASR2LRtYC1MCIvJHDFRKAp9kPJbQo9P37\nZ8IU7cDudkZFgNLmDixlWsh7C0ghX8fgAlj1P6FgsFufygam973k79GhIP54dELB\nc0S6E8ekkRSOXU9jX/IoiXuFglBvFihAdhvED58bMXzj2AwXUyeAlxItnvs+NVUC\nAwEAATANBgkqhkiG9w0BAQUFAAOBgQBkFZRbMoywK3hb0/X7MXmPYa7nlfnd5UXq\nr2n32ettzZNmEPaI2d1j+//nL5qqhOlrWPS88eKEPnBOX/jZpUWOuAAddnrvFzgw\nrp/C2H7oMT+29F+5ezeViLKbzoFYb4yECHBoi66IFXNae13yj7taMboBeUmE664G\nTB/MZpRr8g==\n-----END CERTIFICATE-----\n".freeze
|
8
|
+
PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0sOY9tHvVtLZ6xmVmH8d\n8LrRrNcWOXbrvvCrai+T3GtRvRSLhksLrpOpD0L9EHM6NdThNF/eGA9Oq+UKAe6y\nXR0hwsKuxKXqQ8SEmlhZZ9GiuggDB/zYD3ItB6SGpdkRe7kQqTChQyrIXqbRkJqx\noTXLyeJDF0sCyTdp3L8IZCUWodM8oV9TlQBJHYtG1gLUwIi8kcMVEoCn2Q8ltCj0\n/ftnwhTtwO52RkWA0uYOLGVayHsLSCFfx+ACWPU/oWCwW5/KBqb3veTv0aEg/nh0\nQsFzRLoTx6SRFI5dT2Nf8iiJe4WCUG8WKEB2G8QPnxsxfOPYDBdTJ4CXEi2e+z41\nVQIDAQAB\n-----END PUBLIC KEY-----\n".freeze
|
9
|
+
PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA0sOY9tHvVtLZ6xmVmH8d8LrRrNcWOXbrvvCrai+T3GtRvRSL\nhksLrpOpD0L9EHM6NdThNF/eGA9Oq+UKAe6yXR0hwsKuxKXqQ8SEmlhZZ9GiuggD\nB/zYD3ItB6SGpdkRe7kQqTChQyrIXqbRkJqxoTXLyeJDF0sCyTdp3L8IZCUWodM8\noV9TlQBJHYtG1gLUwIi8kcMVEoCn2Q8ltCj0/ftnwhTtwO52RkWA0uYOLGVayHsL\nSCFfx+ACWPU/oWCwW5/KBqb3veTv0aEg/nh0QsFzRLoTx6SRFI5dT2Nf8iiJe4WC\nUG8WKEB2G8QPnxsxfOPYDBdTJ4CXEi2e+z41VQIDAQABAoIBAALhqbW2KQ+G0nPk\nZacwFbi01SkHx8YBWjfCEpXhEKRy0ytCnKW5YO+CFU2gHNWcva7+uhV9OgwaKXkw\nKHLeUJH1VADVqI4Htqw2g5mYm6BPvWnNsjzpuAp+BR+VoEGkNhj67r9hatMAQr0I\nitTvSH5rvd2EumYXIHKfz1K1SegUk1u1EL1RcMzRmZe4gDb6eNBs9Sg4im4ybTG6\npPIytA8vBQVWhjuAR2Tm+wZHiy0Az6Vu7c2mS07FSX6FO4E8SxWf8idaK9ijMGSq\nFvIS04mrY6XCPUPUC4qm1qNnhDPpOr7CpI2OO98SqGanStS5NFlSFXeXPpM280/u\nfZUA0AECgYEA+x7QUnffDrt7LK2cX6wbvn4mRnFxet7bJjrfWIHf+Rm0URikaNma\nh0/wNKpKBwIH+eHK/LslgzcplrqPytGGHLOG97Gyo5tGAzyLHUWBmsNkRksY2sPL\nuHq6pYWJNkqhnWGnIbmqCr0EWih82x/y4qxbJYpYqXMrit0wVf7yAgkCgYEA1twI\ngFaXqesetTPoEHSQSgC8S4D5/NkdriUXCYb06REcvo9IpFMuiOkVUYNN5d3MDNTP\nIdBicfmvfNELvBtXDomEUD8ls1UuoTIXRNGZ0VsZXu7OErXCK0JKNNyqRmOwcvYL\nJRqLfnlei5Ndo1lu286yL74c5rdTLs/nI2p4e+0CgYB079ZmcLeILrmfBoFI8+Y/\ngJLmPrFvXBOE6+lRV7kqUFPtZ6I3yQzyccETZTDvrnx0WjaiFavUPH27WMjY01S2\nTMtO0Iq1MPsbSrglO1as8MvjB9ldFcvp7gy4Q0Sv6XT0yqJ/S+vo8Df0m+H4UBpU\nf5o6EwBSd/UQxwtZIE0lsQKBgQCswfjX8Eg8KL/lJNpIOOE3j4XXE9ptksmJl2sB\njxDnQYoiMqVO808saHVquC/vTrpd6tKtNpehWwjeTFuqITWLi8jmmQ+gNTKsC9Gn\n1Pxf2Gb67PqnEpwQGln+TRtgQ5HBrdHiQIi+5am+gnw89pDrjjO5rZwhanAo6KPJ\n1zcPNQKBgQDxFu8v4frDmRNCVaZS4f1B6wTrcMrnibIDlnzrK9GG6Hz1U7dDv8s8\nNf4UmeMzDXjlPWZVOvS5+9HKJPdPj7/onv8B2m18+lcgTTDJBkza7R1mjL1Cje/Z\nKcVGsryKN6cjE7yCDasnA7R2rVBV/7NWeJV77bmzT5O//rW4yIfUIg==\n-----END RSA PRIVATE KEY-----\n".freeze
|
10
|
+
end
|