CFPropertyList 2.2.8 → 2.3.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.
- checksums.yaml +4 -4
- data/lib/cfpropertylist/rbCFPropertyList.rb +41 -10
- data/lib/cfpropertylist/rbCFTypes.rb +85 -2
- data/lib/cfpropertylist/rbPlainCFPropertyList.rb +197 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc33e5b367dbce4a691398d57944021021aef03f
|
4
|
+
data.tar.gz: 67607311e62f42c8c7db8e41e318342fbb1188a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22cfa79f7cde0aeaa04896c06dbbe866a9945853903abe3049fc462a60fa7fd031b384d8a1059338d5655a260091fced46909027321b02b0f012d773715b817b
|
7
|
+
data.tar.gz: 3951e013406ade3ef418b75f188e9c48a0ec49f1dda6eec74fa3f2b3aa722e4f9383ad0b98a4707c3a8f53b587d837a893288c4c74b8a81de563adaf907d3bb7
|
@@ -84,6 +84,7 @@ dirname = File.dirname(__FILE__)
|
|
84
84
|
require dirname + '/rbCFPlistError.rb'
|
85
85
|
require dirname + '/rbCFTypes.rb'
|
86
86
|
require dirname + '/rbBinaryCFPropertyList.rb'
|
87
|
+
require dirname + '/rbPlainCFPropertyList.rb'
|
87
88
|
|
88
89
|
require 'iconv' unless "".respond_to?("encode")
|
89
90
|
|
@@ -218,10 +219,13 @@ module CFPropertyList
|
|
218
219
|
# Format constant for XML format
|
219
220
|
FORMAT_XML = 2
|
220
221
|
|
222
|
+
# Format constant for the old plain format
|
223
|
+
FORMAT_PLAIN = 3
|
224
|
+
|
221
225
|
# Format constant for automatic format recognizing
|
222
226
|
FORMAT_AUTO = 0
|
223
227
|
|
224
|
-
@@parsers = [Binary, CFPropertyList.xml_parser_interface]
|
228
|
+
@@parsers = [Binary, CFPropertyList.xml_parser_interface, PlainParser]
|
225
229
|
|
226
230
|
# Path of PropertyList
|
227
231
|
attr_accessor :filename
|
@@ -271,6 +275,12 @@ module CFPropertyList
|
|
271
275
|
load(filename,List::FORMAT_BINARY)
|
272
276
|
end
|
273
277
|
|
278
|
+
# read a plain plist file
|
279
|
+
# filename = nil:: The filename to read from; if nil, read from the file defined by instance variable +filename+
|
280
|
+
def load_plain(filename=nil)
|
281
|
+
load(filename,List::FORMAT_PLAIN)
|
282
|
+
end
|
283
|
+
|
274
284
|
# load a plist from a XML string
|
275
285
|
# str:: The string containing the plist
|
276
286
|
def load_xml_str(str=nil)
|
@@ -283,6 +293,12 @@ module CFPropertyList
|
|
283
293
|
load_str(str,List::FORMAT_BINARY)
|
284
294
|
end
|
285
295
|
|
296
|
+
# load a plist from a plain string
|
297
|
+
# str:: The string containing the plist
|
298
|
+
def load_binary_str(str=nil)
|
299
|
+
load_str(str,List::FORMAT_PLAIN)
|
300
|
+
end
|
301
|
+
|
286
302
|
# load a plist from a string
|
287
303
|
# str = nil:: The string containing the plist
|
288
304
|
# format = nil:: The format of the plist
|
@@ -292,7 +308,7 @@ module CFPropertyList
|
|
292
308
|
|
293
309
|
@value = {}
|
294
310
|
case format
|
295
|
-
when List::FORMAT_BINARY, List::FORMAT_XML then
|
311
|
+
when List::FORMAT_BINARY, List::FORMAT_XML, List::FORMAT_PLAIN then
|
296
312
|
prsr = @@parsers[format-1].new
|
297
313
|
@value = prsr.load({:data => str})
|
298
314
|
|
@@ -301,13 +317,19 @@ module CFPropertyList
|
|
301
317
|
version = str[6..7]
|
302
318
|
|
303
319
|
prsr = nil
|
320
|
+
|
304
321
|
if filetype == "bplist" then
|
305
322
|
raise CFFormatError.new("Wrong file version #{version}") unless version == "00"
|
306
323
|
prsr = Binary.new
|
307
324
|
@format = List::FORMAT_BINARY
|
308
325
|
else
|
309
|
-
|
310
|
-
|
326
|
+
if str =~ /^<(\?xml|!DOCTYPE|plist)/
|
327
|
+
prsr = CFPropertyList.xml_parser_interface.new
|
328
|
+
@format = List::FORMAT_XML
|
329
|
+
else
|
330
|
+
prsr = PlainParser.new
|
331
|
+
@format = List::FORMAT_PLAIN
|
332
|
+
end
|
311
333
|
end
|
312
334
|
|
313
335
|
@value = prsr.load({:data => str})
|
@@ -325,12 +347,12 @@ module CFPropertyList
|
|
325
347
|
raise IOError.new("File #{file} not readable!") unless File.readable? file
|
326
348
|
|
327
349
|
case format
|
328
|
-
when List::FORMAT_BINARY, List::FORMAT_XML then
|
350
|
+
when List::FORMAT_BINARY, List::FORMAT_XML, List::FORMAT_PLAIN then
|
329
351
|
prsr = @@parsers[format-1].new
|
330
352
|
@value = prsr.load({:file => file})
|
331
353
|
|
332
354
|
when List::FORMAT_AUTO then # what we now do is ugly, but neccessary to recognize the file format
|
333
|
-
magic_number = IO.read(file,
|
355
|
+
magic_number = IO.read(file,12)
|
334
356
|
raise IOError.new("File #{file} is empty.") unless magic_number
|
335
357
|
filetype = magic_number[0..5]
|
336
358
|
version = magic_number[6..7]
|
@@ -341,8 +363,13 @@ module CFPropertyList
|
|
341
363
|
prsr = Binary.new
|
342
364
|
@format = List::FORMAT_BINARY
|
343
365
|
else
|
344
|
-
|
345
|
-
|
366
|
+
if magic_number =~ /^<(\?xml|!DOCTYPE|plist)/
|
367
|
+
prsr = CFPropertyList.xml_parser_interface.new
|
368
|
+
@format = List::FORMAT_XML
|
369
|
+
else
|
370
|
+
prsr = PlainParser.new
|
371
|
+
@format = List::FORMAT_PLAIN
|
372
|
+
end
|
346
373
|
end
|
347
374
|
|
348
375
|
@value = prsr.load({:file => file})
|
@@ -358,7 +385,9 @@ module CFPropertyList
|
|
358
385
|
format = @format if format.nil?
|
359
386
|
file = @filename if file.nil?
|
360
387
|
|
361
|
-
|
388
|
+
if format != FORMAT_BINARY && format != FORMAT_XML && format != FORMAT_PLAIN
|
389
|
+
raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML")
|
390
|
+
end
|
362
391
|
|
363
392
|
if(!File.exists?(file)) then
|
364
393
|
raise IOError.new("File #{file} not writable!") unless File.writable?(File.dirname(file))
|
@@ -383,7 +412,9 @@ module CFPropertyList
|
|
383
412
|
# format = List::FORMAT_BINARY:: The format to save the plist
|
384
413
|
# opts={}:: Pass parser options
|
385
414
|
def to_str(format=List::FORMAT_BINARY,opts={})
|
386
|
-
|
415
|
+
if format != FORMAT_BINARY && format != FORMAT_XML && format != FORMAT_PLAIN
|
416
|
+
raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML")
|
417
|
+
end
|
387
418
|
|
388
419
|
prsr = @@parsers[format-1].new
|
389
420
|
|
@@ -37,7 +37,11 @@ module CFPropertyList
|
|
37
37
|
def to_xml(parser)
|
38
38
|
end
|
39
39
|
|
40
|
-
def to_binary(bplist)
|
40
|
+
def to_binary(bplist)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_plain(plist)
|
44
|
+
end
|
41
45
|
end
|
42
46
|
|
43
47
|
# This class holds string values, both, UTF-8 and UTF-16BE
|
@@ -54,6 +58,44 @@ module CFPropertyList
|
|
54
58
|
def to_binary(bplist)
|
55
59
|
bplist.string_to_binary(@value);
|
56
60
|
end
|
61
|
+
|
62
|
+
def to_plain(plist)
|
63
|
+
if @value =~ /^\w+$/
|
64
|
+
@value
|
65
|
+
else
|
66
|
+
quoted
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def quoted
|
71
|
+
str = '"'
|
72
|
+
@value.each_char do |c|
|
73
|
+
str << case c
|
74
|
+
when '"'
|
75
|
+
'\\"'
|
76
|
+
when '\\'
|
77
|
+
'\\'
|
78
|
+
when "\a"
|
79
|
+
"\\a"
|
80
|
+
when "\b"
|
81
|
+
"\\b"
|
82
|
+
when "\f"
|
83
|
+
"\\f"
|
84
|
+
when "\n"
|
85
|
+
"\n"
|
86
|
+
when "\v"
|
87
|
+
"\\v"
|
88
|
+
when "\r"
|
89
|
+
"\\r"
|
90
|
+
when "\t"
|
91
|
+
"\\t"
|
92
|
+
else
|
93
|
+
c
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
str << '"'
|
98
|
+
end
|
57
99
|
end
|
58
100
|
|
59
101
|
# This class holds integer/fixnum values
|
@@ -69,6 +111,10 @@ module CFPropertyList
|
|
69
111
|
def to_binary(bplist)
|
70
112
|
bplist.num_to_binary(self)
|
71
113
|
end
|
114
|
+
|
115
|
+
def to_plain(plist)
|
116
|
+
@value.to_s
|
117
|
+
end
|
72
118
|
end
|
73
119
|
|
74
120
|
# This class holds float values
|
@@ -84,6 +130,10 @@ module CFPropertyList
|
|
84
130
|
def to_binary(bplist)
|
85
131
|
bplist.num_to_binary(self)
|
86
132
|
end
|
133
|
+
|
134
|
+
def to_plain(plist)
|
135
|
+
@value.to_s
|
136
|
+
end
|
87
137
|
end
|
88
138
|
|
89
139
|
# This class holds Time values. While Apple uses seconds since 2001,
|
@@ -92,7 +142,7 @@ module CFPropertyList
|
|
92
142
|
# geht the timestamp or the Apple timestamp
|
93
143
|
class CFDate < CFType
|
94
144
|
TIMESTAMP_APPLE = 0
|
95
|
-
TIMESTAMP_UNIX = 1
|
145
|
+
TIMESTAMP_UNIX = 1
|
96
146
|
DATE_DIFF_APPLE_UNIX = 978307200
|
97
147
|
|
98
148
|
# create a XML date strimg from a time object
|
@@ -151,6 +201,10 @@ module CFPropertyList
|
|
151
201
|
def to_binary(bplist)
|
152
202
|
bplist.date_to_binary(@value)
|
153
203
|
end
|
204
|
+
|
205
|
+
def to_plain(plist)
|
206
|
+
@value.strftime("%Y-%m-%d %H:%M:%S %z")
|
207
|
+
end
|
154
208
|
end
|
155
209
|
|
156
210
|
# This class contains a boolean value
|
@@ -164,6 +218,10 @@ module CFPropertyList
|
|
164
218
|
def to_binary(bplist)
|
165
219
|
bplist.bool_to_binary(@value);
|
166
220
|
end
|
221
|
+
|
222
|
+
def to_plain(plist)
|
223
|
+
@value ? "true" : "false"
|
224
|
+
end
|
167
225
|
end
|
168
226
|
|
169
227
|
# This class contains binary data values
|
@@ -203,6 +261,10 @@ module CFPropertyList
|
|
203
261
|
def to_binary(bplist)
|
204
262
|
bplist.data_to_binary(decoded_value())
|
205
263
|
end
|
264
|
+
|
265
|
+
def to_plain(plist)
|
266
|
+
"<" + decoded_value.unpack("H*").join("") + ">"
|
267
|
+
end
|
206
268
|
end
|
207
269
|
|
208
270
|
# This class contains an array of values
|
@@ -225,6 +287,11 @@ module CFPropertyList
|
|
225
287
|
def to_binary(bplist)
|
226
288
|
bplist.array_to_binary(self)
|
227
289
|
end
|
290
|
+
|
291
|
+
def to_plain(plist)
|
292
|
+
ary = @value.map { |v| v.to_plain(plist) }
|
293
|
+
"( " + ary.join(", ") + " )"
|
294
|
+
end
|
228
295
|
end
|
229
296
|
|
230
297
|
# this class contains a hash of values
|
@@ -249,6 +316,18 @@ module CFPropertyList
|
|
249
316
|
def to_binary(bplist)
|
250
317
|
bplist.dict_to_binary(self)
|
251
318
|
end
|
319
|
+
|
320
|
+
def to_plain(plist)
|
321
|
+
str = "{ "
|
322
|
+
cfstr = CFString.new()
|
323
|
+
|
324
|
+
@value.each do |k,v|
|
325
|
+
cfstr.value = k
|
326
|
+
str << cfstr.to_plain(plist) + " = " + v.to_plain(plist) + "; "
|
327
|
+
end
|
328
|
+
|
329
|
+
str << "}"
|
330
|
+
end
|
252
331
|
end
|
253
332
|
|
254
333
|
class CFUid < CFType
|
@@ -260,6 +339,10 @@ module CFPropertyList
|
|
260
339
|
def to_binary(bplist)
|
261
340
|
bplist.uid_to_binary(@value)
|
262
341
|
end
|
342
|
+
|
343
|
+
def to_plain(plist)
|
344
|
+
CFDictionary.new({'CF$UID' => CFInteger.new(@value)}).to_plain(plist)
|
345
|
+
end
|
263
346
|
end
|
264
347
|
end
|
265
348
|
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
module CFPropertyList
|
6
|
+
# XML parser
|
7
|
+
class PlainParser < XMLParserInterface
|
8
|
+
# read a XML file
|
9
|
+
# opts::
|
10
|
+
# * :file - The filename of the file to load
|
11
|
+
# * :data - The data to parse
|
12
|
+
def load(opts)
|
13
|
+
@doc = nil
|
14
|
+
|
15
|
+
if(opts.has_key?(:file)) then
|
16
|
+
File.open(opts[:file], :external_encoding => "ASCII") do |fd|
|
17
|
+
@doc = StringScanner.new(fd.read)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
@doc = StringScanner.new(opts[:data])
|
21
|
+
end
|
22
|
+
|
23
|
+
if @doc
|
24
|
+
root = import_plain
|
25
|
+
raise CFFormatError.new('content after root object') unless @doc.eos?
|
26
|
+
|
27
|
+
return root
|
28
|
+
end
|
29
|
+
|
30
|
+
raise CFFormatError.new('invalid plist string or file not found')
|
31
|
+
end
|
32
|
+
|
33
|
+
SPACES_AND_COMMENTS = %r{((?:/\*.*?\*/)|(?://.*?$\n?)|(?:\s*))+}x
|
34
|
+
|
35
|
+
# serialize CFPropertyList object to XML
|
36
|
+
# opts = {}:: Specify options: :formatted - Use indention and line breaks
|
37
|
+
def to_str(opts={})
|
38
|
+
opts[:root].to_plain(self)
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
def skip_whitespaces
|
43
|
+
@doc.skip SPACES_AND_COMMENTS
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_dict
|
47
|
+
skip_whitespaces
|
48
|
+
hsh = {}
|
49
|
+
|
50
|
+
while not @doc.scan(/\}/)
|
51
|
+
key = import_plain
|
52
|
+
raise CFFormatError.new("invalid dictionary format") if !key
|
53
|
+
|
54
|
+
if key.is_a?(CFString)
|
55
|
+
key = key.value
|
56
|
+
elsif key.is_a?(CFInteger) or key.is_a?(CFReal)
|
57
|
+
key = key.value.to_s
|
58
|
+
else
|
59
|
+
raise CFFormatError.new("invalid key format")
|
60
|
+
end
|
61
|
+
|
62
|
+
skip_whitespaces
|
63
|
+
|
64
|
+
raise CFFormatError.new("invalid dictionary format") unless @doc.scan(/=/)
|
65
|
+
|
66
|
+
skip_whitespaces
|
67
|
+
val = import_plain
|
68
|
+
|
69
|
+
skip_whitespaces
|
70
|
+
raise CFFormatError.new("invalid dictionary format") unless @doc.scan(/;/)
|
71
|
+
skip_whitespaces
|
72
|
+
|
73
|
+
hsh[key] = val
|
74
|
+
raise CFFormatError.new("invalid dictionary format") if @doc.eos?
|
75
|
+
end
|
76
|
+
|
77
|
+
CFDictionary.new(hsh)
|
78
|
+
end
|
79
|
+
|
80
|
+
def read_array
|
81
|
+
skip_whitespaces
|
82
|
+
ary = []
|
83
|
+
|
84
|
+
while not @doc.scan(/\)/)
|
85
|
+
val = import_plain
|
86
|
+
|
87
|
+
return nil if not val or not val.value
|
88
|
+
skip_whitespaces
|
89
|
+
|
90
|
+
if not @doc.skip(/,\s*/)
|
91
|
+
if @doc.scan(/\)/)
|
92
|
+
ary << val
|
93
|
+
return CFArray.new(ary)
|
94
|
+
end
|
95
|
+
|
96
|
+
raise CFFormatError.new("invalid array format")
|
97
|
+
end
|
98
|
+
|
99
|
+
ary << val
|
100
|
+
raise CFFormatError.new("invalid array format") if @doc.eos?
|
101
|
+
end
|
102
|
+
|
103
|
+
CFArray.new(ary)
|
104
|
+
end
|
105
|
+
|
106
|
+
def escape_char
|
107
|
+
case @doc.matched
|
108
|
+
when '"'
|
109
|
+
'"'
|
110
|
+
when '\\'
|
111
|
+
'\\'
|
112
|
+
when 'a'
|
113
|
+
"\a"
|
114
|
+
when 'b'
|
115
|
+
"\b"
|
116
|
+
when 'f'
|
117
|
+
"\f"
|
118
|
+
when 'n'
|
119
|
+
"\n"
|
120
|
+
when 'v'
|
121
|
+
"\v"
|
122
|
+
when 'r'
|
123
|
+
"\r"
|
124
|
+
when 't'
|
125
|
+
"\t"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def read_quoted
|
130
|
+
str = ''
|
131
|
+
|
132
|
+
while not @doc.scan(/"/)
|
133
|
+
if @doc.scan(/\\/)
|
134
|
+
@doc.scan(/./)
|
135
|
+
str << escape_char
|
136
|
+
|
137
|
+
elsif @doc.eos?
|
138
|
+
raise CFFormatError.new("unterminated string")
|
139
|
+
|
140
|
+
else @doc.scan(/./)
|
141
|
+
str << @doc.matched
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
CFString.new(str)
|
146
|
+
end
|
147
|
+
|
148
|
+
def read_unquoted
|
149
|
+
raise CFFormatError.new("unexpected end of file") if @doc.eos?
|
150
|
+
|
151
|
+
if @doc.scan(/(\d\d\d\d)-(\d\d)-(\d\d)\s+(\d\d):(\d\d):(\d\d)(?:\s+(\+|-)(\d\d)(\d\d))?/)
|
152
|
+
year,month,day,hour,min,sec,pl_min,tz_hour, tz_min = @doc[1], @doc[2], @doc[3], @doc[4], @doc[5], @doc[6], @doc[7], @doc[8], @doc[9]
|
153
|
+
CFDate.new(Time.new(year, month, day, hour, min, sec, pl_min ? sprintf("%s%s:%s", pl_min, tz_hour, tz_min) : nil))
|
154
|
+
|
155
|
+
elsif @doc.scan(/-?\d+?\.\d+\b/)
|
156
|
+
CFReal.new(@doc.matched.to_f)
|
157
|
+
|
158
|
+
elsif @doc.scan(/-?\d+\b/)
|
159
|
+
CFInteger.new(@doc.matched.to_i)
|
160
|
+
|
161
|
+
elsif @doc.scan(/\b(true|false)\b/)
|
162
|
+
CFBoolean.new(@doc.matched == 'true')
|
163
|
+
else
|
164
|
+
CFString.new(@doc.scan(/\w+/))
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def read_binary
|
169
|
+
@doc.scan(/(.*?)>/)
|
170
|
+
|
171
|
+
hex_str = @doc[1].gsub(/ /, '')
|
172
|
+
CFData.new([hex_str].pack("H*"), CFData::DATA_RAW)
|
173
|
+
end
|
174
|
+
|
175
|
+
# import the XML values
|
176
|
+
def import_plain
|
177
|
+
skip_whitespaces
|
178
|
+
ret = nil
|
179
|
+
|
180
|
+
if @doc.scan(/\{/) # dict
|
181
|
+
ret = read_dict
|
182
|
+
elsif @doc.scan(/\(/) # array
|
183
|
+
ret = read_array
|
184
|
+
elsif @doc.scan(/"/) # string
|
185
|
+
ret = read_quoted
|
186
|
+
elsif @doc.scan(/</) # binary
|
187
|
+
ret = read_binary
|
188
|
+
else # string w/o quotes
|
189
|
+
ret = read_unquoted
|
190
|
+
end
|
191
|
+
|
192
|
+
return ret
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# eof
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: CFPropertyList
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Kruse
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -40,6 +40,7 @@ files:
|
|
40
40
|
- lib/cfpropertylist/rbCFTypes.rb
|
41
41
|
- lib/cfpropertylist/rbLibXMLParser.rb
|
42
42
|
- lib/cfpropertylist/rbNokogiriParser.rb
|
43
|
+
- lib/cfpropertylist/rbPlainCFPropertyList.rb
|
43
44
|
- lib/cfpropertylist/rbREXMLParser.rb
|
44
45
|
homepage: http://github.com/ckruse/CFPropertyList
|
45
46
|
licenses:
|
@@ -61,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
62
|
version: '0'
|
62
63
|
requirements: []
|
63
64
|
rubyforge_project:
|
64
|
-
rubygems_version: 2.
|
65
|
+
rubygems_version: 2.4.5
|
65
66
|
signing_key:
|
66
67
|
specification_version: 4
|
67
68
|
summary: Read, write and manipulate both binary and XML property lists as defined
|