jss-api 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGES.md +4 -0
  2. data/LICENSE.txt +174 -0
  3. data/README.md +368 -0
  4. data/THANKS.md +6 -0
  5. data/lib/jss-api.rb +549 -0
  6. data/lib/jss-api/api_connection.rb +326 -0
  7. data/lib/jss-api/api_object.rb +590 -0
  8. data/lib/jss-api/api_object/advanced_search.rb +389 -0
  9. data/lib/jss-api/api_object/advanced_search/advanced_computer_search.rb +95 -0
  10. data/lib/jss-api/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
  11. data/lib/jss-api/api_object/advanced_search/advanced_user_search.rb +95 -0
  12. data/lib/jss-api/api_object/building.rb +92 -0
  13. data/lib/jss-api/api_object/category.rb +147 -0
  14. data/lib/jss-api/api_object/computer.rb +852 -0
  15. data/lib/jss-api/api_object/creatable.rb +98 -0
  16. data/lib/jss-api/api_object/criteriable.rb +189 -0
  17. data/lib/jss-api/api_object/criteriable/criteria.rb +231 -0
  18. data/lib/jss-api/api_object/criteriable/criterion.rb +228 -0
  19. data/lib/jss-api/api_object/department.rb +93 -0
  20. data/lib/jss-api/api_object/distribution_point.rb +490 -0
  21. data/lib/jss-api/api_object/extendable.rb +221 -0
  22. data/lib/jss-api/api_object/extension_attribute.rb +457 -0
  23. data/lib/jss-api/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
  24. data/lib/jss-api/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
  25. data/lib/jss-api/api_object/extension_attribute/user_extension_attribute.rb +117 -0
  26. data/lib/jss-api/api_object/group.rb +380 -0
  27. data/lib/jss-api/api_object/group/computer_group.rb +124 -0
  28. data/lib/jss-api/api_object/group/mobile_device_group.rb +139 -0
  29. data/lib/jss-api/api_object/group/user_group.rb +139 -0
  30. data/lib/jss-api/api_object/ldap_server.rb +535 -0
  31. data/lib/jss-api/api_object/locatable.rb +268 -0
  32. data/lib/jss-api/api_object/matchable.rb +97 -0
  33. data/lib/jss-api/api_object/mobile_device.rb +556 -0
  34. data/lib/jss-api/api_object/netboot_server.rb +148 -0
  35. data/lib/jss-api/api_object/network_segment.rb +414 -0
  36. data/lib/jss-api/api_object/package.rb +760 -0
  37. data/lib/jss-api/api_object/peripheral.rb +335 -0
  38. data/lib/jss-api/api_object/peripheral_type.rb +295 -0
  39. data/lib/jss-api/api_object/policy.rb +882 -0
  40. data/lib/jss-api/api_object/purchasable.rb +316 -0
  41. data/lib/jss-api/api_object/removable_macaddr.rb +98 -0
  42. data/lib/jss-api/api_object/scopable.rb +136 -0
  43. data/lib/jss-api/api_object/scopable/scope.rb +621 -0
  44. data/lib/jss-api/api_object/script.rb +631 -0
  45. data/lib/jss-api/api_object/site.rb +93 -0
  46. data/lib/jss-api/api_object/software_update_server.rb +109 -0
  47. data/lib/jss-api/api_object/updatable.rb +117 -0
  48. data/lib/jss-api/api_object/uploadable.rb +138 -0
  49. data/lib/jss-api/api_object/user.rb +272 -0
  50. data/lib/jss-api/client.rb +500 -0
  51. data/lib/jss-api/compatibility.rb +66 -0
  52. data/lib/jss-api/composer.rb +171 -0
  53. data/lib/jss-api/configuration.rb +301 -0
  54. data/lib/jss-api/db_connection.rb +243 -0
  55. data/lib/jss-api/exceptions.rb +83 -0
  56. data/lib/jss-api/ruby_extensions.rb +35 -0
  57. data/lib/jss-api/ruby_extensions/filetest.rb +43 -0
  58. data/lib/jss-api/ruby_extensions/hash.rb +79 -0
  59. data/lib/jss-api/ruby_extensions/ipaddr.rb +91 -0
  60. data/lib/jss-api/ruby_extensions/pathname.rb +77 -0
  61. data/lib/jss-api/ruby_extensions/string.rb +43 -0
  62. data/lib/jss-api/ruby_extensions/time.rb +63 -0
  63. data/lib/jss-api/server.rb +108 -0
  64. data/lib/jss-api/version.rb +31 -0
  65. metadata +219 -0
@@ -0,0 +1,98 @@
1
+ ### Copyright 2014 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ #####################################
29
+ ### Module Variables
30
+ #####################################
31
+
32
+
33
+ #####################################
34
+ ### Module Methods
35
+ #####################################
36
+
37
+ #####################################
38
+ ### Sub-Modules
39
+ #####################################
40
+
41
+ ###
42
+ ### A mix-in module that allows objects to be created in the JSS
43
+ ### via the API.
44
+ ###
45
+ ### When a JSS::APIObject subclass includes this module, that subclass
46
+ ### can be instantiated with :id => :new, and :name => "some_new_name".
47
+ ###
48
+ ### The instance can be used to set desired values for the new object, and
49
+ ### once everything's good, use #create to create it in the JSS.
50
+ ###
51
+ ### If a Creatable object requires more data than just a :name for creation,
52
+ ### the subclass may want to redefine #initialize to require those data before
53
+ ### calling super.
54
+ ###
55
+ ### Some subclasses may want to redefine #create to check
56
+ ### the data for consistency, and then call super
57
+ ### (or they may have the individual setter methods do the checks)
58
+ ###
59
+ ### Classes mixing this module *must* provide a #rest_xml instance method that returns the XML
60
+ ### String to be submitted to the API for object creation.
61
+ ###
62
+ ### @see APIObject#save
63
+ ###
64
+ module Creatable
65
+
66
+ #####################################
67
+ ### Constants
68
+ #####################################
69
+
70
+ CREATABLE = true
71
+
72
+ #####################################
73
+ ### Variables
74
+ #####################################
75
+
76
+ #####################################
77
+ ### Mixed-in Instance Methods
78
+ #####################################
79
+
80
+ ###
81
+ ### Create a new object in the JSS.
82
+ ###
83
+ ### @return [Integer] the jss ID of the newly created object
84
+ ###
85
+ def create
86
+ raise JSS::UnsupportedError, "Creating or editing #{self.class::RSRC_LIST_KEY} isn't yet supported. Please use other Casper workflows." unless CREATABLE
87
+ raise AlreadyExistsError, "This #{self.class::RSRC_OBJECT_KEY} already exists. Use #update to make changes." if @in_jss
88
+ JSS::API.post_rsrc( @rest_rsrc, rest_xml) =~ /><id>(\d+)<\/id></
89
+ @id = $1.to_i
90
+ @in_jss = true
91
+ @need_to_update = false
92
+ @rest_rsrc = "#{self.class::RSRC_BASE}/id/#{@id}"
93
+ return @id
94
+ end
95
+
96
+ end # module Creatable
97
+
98
+ end # module
@@ -0,0 +1,189 @@
1
+ ### Copyright 2014 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+
29
+ ### A mix-in module providing consistent access to JSS::Criteriable::Criteria and
30
+ ### JSS::Criteriable::Criterion objects from within objects that contain Criteria.
31
+ ###
32
+ ###
33
+
34
+
35
+ #####################################
36
+ ### Module Variables
37
+ #####################################
38
+
39
+
40
+ #####################################
41
+ ### Module Methods
42
+ #####################################
43
+
44
+ #####################################
45
+ ### Sub-Modules
46
+ #####################################
47
+
48
+ ###
49
+ ### A mix-in module that allows objects to handle standardized search Criteria.
50
+ ###
51
+ ### Some objects in the JSS, such as Advanced Searches and Smart Groups,
52
+ ### include a set of Criteria. (i.e conditions which, when met, signify inclusion
53
+ ### in some result set.)
54
+ ###
55
+ ### A {JSS::Criteriable::Criteria} instance is a container for one or more
56
+ ### {JSS::Criteriable::Criterion} instances and provides methods for dealing with
57
+ ### them easily.
58
+ ###
59
+ ### When a {JSS::APIObject} subclass includes this module, that subclass
60
+ ### will have a :criteria attribute, which holds a {JSS::Criteriable::Criteria}
61
+ ### object and can be used to manipulate the Criterion objects inside.
62
+ ###
63
+ ### The including subclass also gains some instance methods:
64
+ ### * #parse_critera - sets up the :criteria attribute during initialization
65
+ ### * #criteria= - allows the wholesale replacement of the criteria
66
+ ### * #need_to_update - allows the {JSS::Criteriable::Criteria} instance to
67
+ ### inform the subclass instance that it has changed and needs an #update
68
+ ###
69
+ ### Classes mixing in this module *must*
70
+ ### * call #parse_criteria during initialization.
71
+ ### * If they are Updatable or Creatable, they must insert
72
+ ### self.criteria.rest_xml into their own xml output.
73
+ ###
74
+ ###
75
+ ### @example Working with the criteria of an advanced search
76
+ ### # create a couple of Criterion instances
77
+ ### crtn_0 = JSS::Criteriable::Criterion.new :and_or => :or, :name => "Username", :search_type => "is", :value => "jeauxbleaux"
78
+ ### crtn_1 = JSS::Criteriable::Criterion.new :and_or => :and, :name => "Last Check-in", :search_type => "less than x days ago", :value => 3
79
+ ###
80
+ ### # use them to create a Criteria instance
81
+ ### crta = JSS::Criteriable::Criteria.new [crtn_0, crtn_1]
82
+ ###
83
+ ### # create a new Advanced Search
84
+ ### srch = JSS::AdvancedComputerSearch.new :id => :new, :name => "my computer search"
85
+ ### srch.display_fields = ["Computer Name"]
86
+ ###
87
+ ### # add our Criteria to it
88
+ ### srch.criteria = crta
89
+ ###
90
+ ### # create it in the JSS
91
+ ### srch.create # srch.search_results now contains the matching computers
92
+ ###
93
+ ### # append a new criterion to the criteria, limiting the search results farther
94
+ ### srch.criteria.append_criterion JSS::Criteriable::Criterion.new(:and_or => :or, :name => "Computer Name", :search_type => "like", :value => "o")
95
+ ###
96
+ ### # save the change to the JSS
97
+ ### srch.save # srch.search_results now contains the matching computers
98
+ ###
99
+ ### # oops - that last one should have been :and, not :or
100
+ ### srch.criteria.criteria[2].and_or = :and
101
+ ###
102
+ ### # the above can also be achieved like this, by replacing the last criterion altogether:
103
+ ### srch.criteria.set_criterion 2, JSS::Criteriable::Criterion.new(:and_or => :and, :name => "Computer Name", :search_type => "like", :value => "o")
104
+ ###
105
+ ### # save the change to the JSS
106
+ ### srch.save # srch.search_results now contains the matching computers
107
+ ###
108
+ ### @see JSS::Criteriable::Criteria
109
+ ### @see JSS::Criteriable::Criterion
110
+ ###
111
+ module Criteriable
112
+
113
+ #####################################
114
+ ### Constants
115
+ #####################################
116
+
117
+ CRITERIABLE = true
118
+
119
+
120
+ #####################################
121
+ ### Variables
122
+ #####################################
123
+
124
+ #####################################
125
+ ### Mixed-in Attributes
126
+ #####################################
127
+
128
+ ### @return [JSS::Criteriable::Criteria] the criteria for the instance into which we're mixed.
129
+ attr_reader :criteria
130
+
131
+ #####################################
132
+ ### Mixed-in Instance Methods
133
+ #####################################
134
+
135
+ ###
136
+ ### During initialization, convert the @init_data[:criteria] Hash into
137
+ ### a JSS::Criteriable::Criteria instance stored in @criteria
138
+ ###
139
+ ### Classes mixing in this module must call this in #initialize
140
+ ###
141
+ ### @return [void]
142
+ ###
143
+ def parse_criteria
144
+ @criteria = if @init_data[:criteria]
145
+ JSS::Criteriable::Criteria.new @init_data[:criteria].map{|c| JSS::Criteriable::Criterion.new c}
146
+ else
147
+ nil
148
+ end
149
+ @criteria.container = self if @criteria
150
+ end
151
+
152
+ ###
153
+ ### Change the criteria, it must be a JSS::Criteriable::Criteria instance
154
+ ###
155
+ ### @param new_criteria[JSS::Criteriable::Criteria] the new criteria
156
+ ###
157
+ ### @return [void]
158
+ ###
159
+ def criteria= (new_criteria)
160
+ raise JSS::InvalidDataError, "JSS::Criteriable::Criteria instance required" unless new_criteria.kind_of?(JSS::Criteriable::Criteria)
161
+ @criteria = new_criteria
162
+ @criteria.container = self
163
+ @need_to_update = true
164
+ end
165
+
166
+ ###
167
+ ###
168
+ ### @api private
169
+ ### Allow our Criteria to tell us when there's been a change that needs
170
+ ### to be updated.
171
+ ###
172
+ ### @return [void]
173
+ ###
174
+ def should_update
175
+ @need_to_update = true if @in_jss
176
+ end
177
+
178
+ #####################################
179
+ ### Mixed-in Class Methods
180
+ #####################################
181
+
182
+
183
+
184
+ end # module Criteriable
185
+
186
+ end # module JSS
187
+
188
+ require "jss-api/api_object/criteriable/criterion"
189
+ require "jss-api/api_object/criteriable/criteria"
@@ -0,0 +1,231 @@
1
+ ### Copyright 2014 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+ module Criteriable
28
+
29
+ #####################################
30
+ ### Module Variables
31
+ #####################################
32
+
33
+ #####################################
34
+ ### Module Methods
35
+ #####################################
36
+
37
+ #####################################
38
+ ### Classes
39
+ #####################################
40
+
41
+ ### This class stores an array of {JSS::Criteriable::Criterion} instances
42
+ ### and provides methods for working with them as a group.
43
+ ###
44
+ ### {JSS::APIObject} subclasses that include {JSS::Criteriable} have a :criteria attribute
45
+ ### which holds one Criteria object.
46
+ ###
47
+ ### Objects that contain Criteria objects need to
48
+ ### - call '#container = self' on their Criteria object when its created.
49
+ ### - implement #should_update, which the Criteria object calls when it changes.
50
+ ###
51
+ ### Both of those tasks are handled by the {JSS::Criteriable} module and are mixed in when
52
+ ### it's included.
53
+ ###
54
+ ### See {JSS::Criteriable} for examples
55
+ ###
56
+ class Criteria
57
+
58
+ #####################################
59
+ ### Class Constants
60
+ #####################################
61
+
62
+ ### Criterion instances we maintain need these attributes.s
63
+ CRITERION_ATTRIBUTES = [:priority, :and_or, :name, :search_type, :value]
64
+
65
+ #####################################
66
+ ### Attributes
67
+ #####################################
68
+
69
+ ### @return [Array] the group of JSS::Criteriable::Criterion instances making up these Criteria
70
+ attr_reader :criteria
71
+
72
+ ### @return [JSS::APIObject subclass] a reference to the object containing these Criteria
73
+ attr_reader :container
74
+
75
+ ###
76
+ ### @param new_criteria[Array<JSS::Criteriable::Criterion>]
77
+ ###
78
+ def initialize(new_criteria)
79
+ @criteria = []
80
+ self.criteria = new_criteria
81
+ end # init
82
+
83
+ ### set the object we belong to, so we can set its @should_update value
84
+ def container= (a_thing)
85
+ @container = a_thing
86
+ end
87
+
88
+ ###
89
+ ### Provide a whole new array of JSS::Criteriable::Criterion instances for this Criteria
90
+ ###
91
+ ### @param new_criteria[Array<JSS::Criteriable::Criterion>]
92
+ ###
93
+ ### @return [void]
94
+ ###
95
+ def criteria= (new_criteria)
96
+ unless new_criteria.kind_of? Array and new_criteria.reject{|c| c.kind_of? JSS::Criteriable::Criterion }.empty?
97
+ raise JSS::InvalidDataError, "Argument must be an Array of JSS::Criteriable::Criterion instances."
98
+ end
99
+ new_criteria.each{ |nc| criterion_ok? nc }
100
+ @criteria = new_criteria
101
+ set_priorities
102
+ @container.should_update if @container
103
+ end
104
+
105
+ ###
106
+ ### Add a new criterion to the end of the criteria
107
+ ###
108
+ ### @param criterion[JSS::Criteriable::Criterion] the new Criterion to store
109
+ ###
110
+ ### @return [void]
111
+ ###
112
+ def append_criterion(criterion)
113
+ criterion_ok? criterion
114
+ criterion.priority = @criteria.length
115
+ @criteria << criterion
116
+ @container.should_update if @container
117
+ end
118
+
119
+ ###
120
+ ### Add a new criterion to the beginning of the criteria
121
+ ###
122
+ ### @param criterion[JSS::Criteriable::Criterion] the new Criterion to store
123
+ ###
124
+ ### @return [void]
125
+ ###
126
+ def prepend_criterion(criterion)
127
+ criterion_ok? criterion
128
+ @criteria.unshift criterion
129
+ set_priorities
130
+ @container.should_update if @container
131
+ end
132
+
133
+ ###
134
+ ### Add a new criterion to the middle of the criteria
135
+ ###
136
+ ### @param priority[Integer] the priority/index before which to insert the new one.
137
+ ###
138
+ ### @param criterion[JSS::Criteriable::Criterion] the new Criterion to store at that index
139
+ ###
140
+ ### @return [void]
141
+ ###
142
+ def insert_criterion(priority,criterion)
143
+ criterion_ok? criterion
144
+ @criteria.insert criterion[:priority], criterion
145
+ set_priorities
146
+ @container.should_update if @container
147
+ end
148
+
149
+ ###
150
+ ### Remove a criterion from the criteria
151
+ ###
152
+ ### @param priority[Integer] the priority/index of the criterion to delete
153
+ ###
154
+ ### @return [void]
155
+ ###
156
+ def delete_criterion(priority)
157
+ if @criteria[priority]
158
+ raise JSS::MissingDataError, "Criteria can't be empty" if @criteria.count == 1
159
+ @criteria.delete_at priority
160
+ set_priorities
161
+ end
162
+ @container.should_update if @container
163
+ end
164
+
165
+ ###
166
+ ### Change the details of one specific criterion
167
+ ###
168
+ ### @param priority[Integer] the priority/index of the criterion being changed.
169
+ ### The index must already exist. Otherwise use
170
+ ### #append_criterion, #prepend_criterion, or #insert_criterion
171
+ ###
172
+ ### @param criterion[JSS::Criteriable::Criterion] the new Criterion to store at that index
173
+ ###
174
+ ### @return [void]
175
+ ###
176
+ def set_criterion(priority, criterion)
177
+ raise JSS::NoSuchItemError, "No current criterion with priority '#{priority}'" unless @criteria[priority]
178
+ criterion_ok? criterion
179
+ @criteria[priority] = criterion
180
+ set_priorities
181
+ @container.should_update if @container
182
+ end
183
+
184
+ ###
185
+ ### Set the priorities of the @criteria to match their array indices
186
+ ###
187
+ ### @return [void]
188
+ ###
189
+ def set_priorities
190
+ @criteria.each_index{ |ci| @criteria[ci].priority = ci }
191
+ end
192
+
193
+ ###
194
+ ### @return [REXML::Element] the xml element for the criteria
195
+ ###
196
+ ### @note This can't be a private method for this class since container classes must call it
197
+ ###
198
+ ### @api private
199
+ ###
200
+ def rest_xml
201
+ raise JSS::MissingDataError, "Criteria can't be empty" if @criteria.empty?
202
+ cr = REXML::Element.new 'criteria'
203
+ @criteria.each { |c| cr << c.rest_xml }
204
+ return cr
205
+ end # rest_xml
206
+
207
+ #####################################
208
+ ### Private Instance Methods
209
+ #####################################
210
+ private
211
+
212
+
213
+ ###
214
+ ### Chech the validity of a criterion.
215
+ ### Note that this doesn't check the :priority
216
+ ### which is set by methods calling this one.
217
+ ###
218
+ ### Return true or raise an error about the problem
219
+ ###
220
+ def criterion_ok? (criterion)
221
+ raise JSS::InvalidDataError, "Duplicate criterion: #{criterion.signature.join(', ')}" if @criteria.select{|c| c == criterion}.count > 1
222
+ raise JSS::InvalidDataError, "Missing :and_or for criterion: #{criterion.signature.join(', ')}" unless criterion.and_or
223
+ raise JSS::InvalidDataError, "Missing :name for criterion: #{criterion.signature.join(', ')}" unless criterion.name
224
+ raise JSS::InvalidDataError, "Missing :search_type for criterion: #{criterion.signature.join(', ')}" unless criterion.search_type
225
+ raise JSS::InvalidDataError, "Missing :value for criterion: #{criterion.signature.join(', ')}" unless criterion.value
226
+ true
227
+ end
228
+
229
+ end # class Criteria
230
+ end # module Criteriable
231
+ end # module