plist4r 0.1.1 → 0.2.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.
- data/README.rdoc +6 -2
- data/VERSION +1 -1
- data/lib/plist4r.rb +9 -4
- data/lib/plist4r/backend.rb +3 -3
- data/lib/plist4r/backend/example.rb +5 -4
- data/lib/plist4r/backend/plutil.rb +11 -10
- data/lib/plist4r/backend/ruby_cocoa.rb +40 -36
- data/lib/plist4r/config.rb +9 -6
- data/lib/plist4r/mixin/data_methods.rb +22 -4
- data/lib/plist4r/mixin/ordered_hash.rb +4 -3
- data/lib/plist4r/plist.rb +72 -39
- data/lib/plist4r/plist_cache.rb +14 -7
- data/lib/plist4r/plist_type.rb +37 -3
- data/lib/plist4r/plist_type/info.rb +6 -0
- data/lib/plist4r/plist_type/launchd.rb +2 -3
- data/lib/plist4r/plist_type/plist.rb +3 -0
- data/plist4r.gemspec +6 -7
- data/plists/{com.adobe.PDFAdminSettings.plist → example_big_binary.plist} +0 -0
- data/plists/{test.plist → example_medium_binary_launchd.plist} +0 -0
- data/plists/{foofoo.xml → example_medium_launchd.xml} +0 -0
- data/plists/{com.apple.SoftwareUpdate.plist → mini.xml} +0 -0
- data/test.rb +28 -3
- metadata +6 -7
- data/plists/Picture of Today.plist +0 -75
data/README.rdoc
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
Welcome to Plist4r, a ruby library for reading and writing plist files.
|
4
4
|
|
5
|
-
Current
|
5
|
+
Current status: `Beta`, 0.2.x series
|
6
|
+
|
7
|
+
We can read / write a `:launchd` plist. So thats pretty good. The API interfaces (for the pluggable backends and plist_types) are not going to change any more. The user API seems to work. If anyone would like to review the Plist4r code and give feedback / suggestions. Now is the time (whilst were still in beta).
|
8
|
+
|
9
|
+
Future `Stable` will be targeted, 0.3.x series.
|
6
10
|
|
7
11
|
== Installation
|
8
12
|
|
@@ -107,7 +111,7 @@ We believe thats allright for most uses, and decided to include `next_step` for
|
|
107
111
|
|
108
112
|
== Remaining Work
|
109
113
|
|
110
|
-
Plist4r
|
114
|
+
Plist4r has now moved from alpha to beta - quality software. TBC...
|
111
115
|
|
112
116
|
* Regression Tests (rspec)
|
113
117
|
* Test harness for the backends
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/plist4r.rb
CHANGED
@@ -18,18 +18,23 @@ module Plist4r
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def string_detect_format string
|
21
|
-
|
22
|
-
|
21
|
+
# puts "in string_detect_format"
|
22
|
+
# puts "string = #{string.inspect}"
|
23
|
+
# s = string.strip
|
24
|
+
string.strip! if string[0,1] =~ /\s/
|
25
|
+
# s = string
|
26
|
+
# puts "s = #{s.inspect}"
|
27
|
+
case string[0,1]
|
23
28
|
when "{","("
|
24
29
|
:next_step
|
25
30
|
when "b"
|
26
|
-
if
|
31
|
+
if string =~ /^bplist/
|
27
32
|
:binary
|
28
33
|
else
|
29
34
|
nil
|
30
35
|
end
|
31
36
|
when "<"
|
32
|
-
if
|
37
|
+
if string =~ /^\<\?xml/ && string =~ /\<\!DOCTYPE plist/
|
33
38
|
:xml
|
34
39
|
else
|
35
40
|
nil
|
data/lib/plist4r/backend.rb
CHANGED
@@ -21,11 +21,11 @@ module Plist4r
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
# vv We
|
24
|
+
# vv We need a version of this to call our matrix test harness vv
|
25
25
|
|
26
26
|
def call method_sym, *args, &blk
|
27
|
-
puts "in call"
|
28
|
-
puts "#{method_sym.inspect} #{args.inspect}"
|
27
|
+
# puts "in call"
|
28
|
+
# puts "#{method_sym.inspect} #{args.inspect}"
|
29
29
|
raise "Unsupported api call #{method_sym.inspect}" unless ApiMethods.include? method_sym.to_s
|
30
30
|
exceptions = []
|
31
31
|
@backends.each do |backend|
|
@@ -3,15 +3,16 @@ require 'plist4r/backend_base'
|
|
3
3
|
|
4
4
|
module Plist4r::Backend::Example
|
5
5
|
class << self
|
6
|
-
def from_string plist
|
7
|
-
|
6
|
+
def from_string plist
|
7
|
+
plist_string = plist.from_string
|
8
|
+
plist_format = Plist4r.string_detect_format plist.from_string
|
8
9
|
unless [:supported_fmt1,:supported_fmt2].include? plist_format
|
9
10
|
raise "#{self} - cant convert string of format #{plist_format}"
|
10
11
|
end
|
11
12
|
hash = ::ActiveSupport::OrderedHash.new
|
12
13
|
# import / convert plist data into ruby ordered hash
|
13
14
|
plist.import_hash hash
|
14
|
-
plist.file_format
|
15
|
+
plist.file_format plist_format
|
15
16
|
return plist
|
16
17
|
end
|
17
18
|
|
@@ -43,7 +44,7 @@ module Plist4r::Backend::Example
|
|
43
44
|
hash = ::ActiveSupport::OrderedHash.new
|
44
45
|
# import / convert plist data into ruby ordered hash
|
45
46
|
plist.import_hash hash
|
46
|
-
plist.file_format
|
47
|
+
plist.file_format file_format
|
47
48
|
return plist
|
48
49
|
end
|
49
50
|
|
@@ -2,18 +2,19 @@
|
|
2
2
|
require 'plist4r/backend_base'
|
3
3
|
|
4
4
|
module Plist4r::Backend::Plutil
|
5
|
-
# maybe this
|
5
|
+
# maybe this could be useful as a helper, used by other backends
|
6
6
|
class << self
|
7
|
-
|
8
|
-
|
7
|
+
def convert_file_to_xml
|
8
|
+
system "plutil -convert xml1 #{@filename}"
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
def convert_file_to_binary
|
12
|
+
system "plutil -convert binary1 #{@filename}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate
|
16
|
+
system "plutil #{@filename}"
|
17
|
+
end
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
@@ -6,16 +6,17 @@ module Plist4r::Backend::RubyCocoa
|
|
6
6
|
def ruby_cocoa_wrapper_rb
|
7
7
|
@ruby_cocoa_wrapper_rb ||= <<-'EOC'
|
8
8
|
#!/usr/bin/ruby
|
9
|
+
raise "No path given to plist4r" unless ARGV[0] && File.exists?("#{ARGV[0]}/plist4r.rb")
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
ordered_hash_rb = ARGV[0]
|
11
|
+
dir = ARGV[0]
|
12
|
+
$LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
|
13
13
|
|
14
|
-
require
|
14
|
+
require 'plist4r/mixin/ordered_hash'
|
15
|
+
require 'osx/cocoa'
|
15
16
|
|
16
17
|
class OSX::NSObject
|
17
18
|
def to_ruby
|
18
|
-
case self
|
19
|
+
case self
|
19
20
|
when OSX::NSDate
|
20
21
|
self.to_time
|
21
22
|
when OSX::NSCFBoolean
|
@@ -45,12 +46,13 @@ end
|
|
45
46
|
module Plist
|
46
47
|
def to_xml hash
|
47
48
|
# to_plist defaults to NSPropertyListXMLFormat_v1_0
|
48
|
-
x = hash.
|
49
|
+
x = hash.to_plist
|
49
50
|
puts "#{x}"
|
50
51
|
end
|
52
|
+
|
51
53
|
def to_binary hash
|
52
54
|
# Here 200 == NSPropertyListBinaryFormat_v1_0
|
53
|
-
x = hash.
|
55
|
+
x = hash.to_plist 200
|
54
56
|
puts "#{x}"
|
55
57
|
end
|
56
58
|
|
@@ -78,15 +80,8 @@ class RubyCocoaWrapper
|
|
78
80
|
include Plist
|
79
81
|
|
80
82
|
def exec stdin
|
81
|
-
|
82
|
-
|
83
|
-
instance_eval stdin
|
84
|
-
exit 0
|
85
|
-
rescue LoadError
|
86
|
-
raise $!
|
87
|
-
rescue
|
88
|
-
raise $!
|
89
|
-
end
|
83
|
+
instance_eval stdin
|
84
|
+
exit 0
|
90
85
|
end
|
91
86
|
end
|
92
87
|
|
@@ -104,16 +99,16 @@ EOC
|
|
104
99
|
require 'plist4r/mixin/popen4'
|
105
100
|
|
106
101
|
unless @rb_script && File.exists?(@rb_script.path)
|
107
|
-
@rb_script
|
108
|
-
|
109
|
-
|
102
|
+
@rb_script = Tempfile.new "ruby_cocoa_wrapper.rb."
|
103
|
+
@rb_script.puts ruby_cocoa_wrapper_rb
|
104
|
+
@rb_script.close
|
110
105
|
File.chmod 0755, @rb_script.path
|
111
106
|
end
|
112
|
-
|
107
|
+
|
108
|
+
plist4r_root = File.expand_path File.join(File.dirname(__FILE__), "..", "..")
|
113
109
|
cmd = @rb_script.path
|
114
|
-
ordered_hash_rb = File.join(File.dirname(__FILE__), "..", "mixin", "ordered_hash.rb")
|
115
110
|
|
116
|
-
pid, stdin, stdout, stderr = ::Plist4r::Popen4::popen4 cmd,
|
111
|
+
pid, stdin, stdout, stderr = ::Plist4r::Popen4::popen4 [cmd, plist4r_root]
|
117
112
|
|
118
113
|
stdin.puts stdin_str
|
119
114
|
|
@@ -126,16 +121,12 @@ EOC
|
|
126
121
|
return [cmd, status, stdout_result, stderr_result]
|
127
122
|
end
|
128
123
|
|
129
|
-
def from_string plist, string
|
130
|
-
raise "method not implemented yet (unfinished)"
|
131
|
-
end
|
132
|
-
|
133
124
|
def to_xml plist
|
134
125
|
hash = plist.to_hash
|
135
|
-
result = ruby_cocoa_exec "to_xml(
|
126
|
+
result = ruby_cocoa_exec "to_xml(#{hash.inspect})"
|
136
127
|
case result[1].exitstatus
|
137
128
|
when 0
|
138
|
-
xml_string =
|
129
|
+
xml_string = result[2]
|
139
130
|
return xml_string
|
140
131
|
else
|
141
132
|
$stderr.puts result[3]
|
@@ -145,40 +136,53 @@ EOC
|
|
145
136
|
|
146
137
|
def to_binary plist
|
147
138
|
hash = plist.to_hash
|
148
|
-
result = ruby_cocoa_exec "to_binary(
|
139
|
+
result = ruby_cocoa_exec "to_binary(#{hash.inspect})"
|
149
140
|
case result[1].exitstatus
|
150
141
|
when 0
|
151
|
-
binary_string =
|
142
|
+
binary_string = result[2]
|
152
143
|
return binary_string
|
153
144
|
else
|
154
145
|
$stderr.puts result[3]
|
155
146
|
raise "Error executing #{result[0]}. See stderr for more information"
|
156
147
|
end
|
157
148
|
end
|
158
|
-
|
159
|
-
def
|
160
|
-
filename = plist.filename
|
149
|
+
|
150
|
+
def open_with_args plist, filename
|
161
151
|
result = ruby_cocoa_exec "open(\"#{filename}\")"
|
162
152
|
case result[1].exitstatus
|
163
153
|
when 0
|
164
|
-
hash =
|
154
|
+
hash = ::ActiveSupport::OrderedHash.new
|
155
|
+
eval("hash.replace("+result[2]+")")
|
165
156
|
plist.import_hash hash
|
166
157
|
else
|
167
158
|
$stderr.puts result[3]
|
168
159
|
raise "Error executing #{result[0]}. See stderr for more information"
|
169
160
|
end
|
170
161
|
file_format = Plist4r.file_detect_format filename
|
171
|
-
plist.file_format
|
162
|
+
plist.file_format file_format
|
172
163
|
return plist
|
173
164
|
end
|
174
165
|
|
166
|
+
def from_string plist
|
167
|
+
require 'tempfile'
|
168
|
+
tf = Tempfile.new "from_string.plist."
|
169
|
+
tf.write plist.from_string
|
170
|
+
tf.close
|
171
|
+
filename = tf.path
|
172
|
+
return open_with_args plist, filename
|
173
|
+
end
|
174
|
+
|
175
|
+
def open plist
|
176
|
+
return open_with_args plist, plist.filename
|
177
|
+
end
|
178
|
+
|
175
179
|
def save hash, filename, file_format
|
176
180
|
filename = plist.filename_path
|
177
181
|
file_format = plist.file_format || Config[:default_format]
|
178
182
|
raise "#{self} - cant save file of format #{file_format}" unless [:xml,:binary].include? file_format
|
179
183
|
|
180
184
|
hash = plist.to_hash
|
181
|
-
result = ruby_cocoa_exec "save(\"#{hash}\",#{filename},#{file_format})"
|
185
|
+
result = ruby_cocoa_exec "save(\"#{hash.inspect}\",#{filename},#{file_format})"
|
182
186
|
case result[1].exitstatus
|
183
187
|
when 0
|
184
188
|
return true
|
data/lib/plist4r/config.rb
CHANGED
@@ -7,15 +7,18 @@ module Plist4r
|
|
7
7
|
class Config
|
8
8
|
extend Mixlib::Config
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
types [] << Dir.glob(File.dirname(__FILE__) + "/plist_type/**/*.rb").collect {|b| File.basename(b,".rb") }
|
11
|
+
types.flatten!.uniq!
|
12
|
+
|
13
|
+
backends ["ruby_cocoa","haml","libxml4r"]
|
14
|
+
backends << Dir.glob(File.dirname(__FILE__) + "/backend/**/*.rb").collect {|b| File.basename(b,".rb") }
|
15
|
+
backends.flatten!.uniq!
|
15
16
|
|
16
17
|
unsupported_keys true
|
17
|
-
raise_any_failure
|
18
|
+
raise_any_failure true
|
18
19
|
deafult_format :xml
|
19
20
|
default_path nil
|
20
21
|
end
|
21
22
|
end
|
23
|
+
|
24
|
+
|
@@ -1,4 +1,5 @@
|
|
1
1
|
|
2
|
+
require 'plist4r/config'
|
2
3
|
require 'plist4r/mixin/ordered_hash'
|
3
4
|
|
4
5
|
module Plist4r
|
@@ -21,13 +22,26 @@ module Plist4r
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def method_missing method_symbol, *args, &blk
|
24
|
-
puts "method_missing: #{method_symbol.inspect}, args: #{args.inspect}"
|
25
|
+
# puts "method_missing: #{method_symbol.inspect}, args: #{args.inspect}"
|
26
|
+
# puts "@hash = #{@hash.inspect}"
|
27
|
+
# puts "hi"
|
25
28
|
valid_keys.each do |key_type, valid_keys_of_those_type|
|
26
29
|
if valid_keys_of_those_type.include?(method_symbol.to_s.camelcase)
|
27
30
|
puts "key_type = #{key_type}, method_symbol.to_s.camelcase = #{method_symbol.to_s.camelcase}, args = #{args.inspect}"
|
28
|
-
return eval("set_or_return key_type, method_symbol.to_s.camelcase, *args, &blk")
|
31
|
+
# return eval("set_or_return key_type, method_symbol.to_s.camelcase, *args, &blk")
|
32
|
+
return set_or_return key_type, method_symbol.to_s.camelcase, *args, &blk
|
29
33
|
end
|
30
34
|
end
|
35
|
+
# puts "there"
|
36
|
+
# puts @plist.inspect
|
37
|
+
if @plist.unsupported_keys
|
38
|
+
key_type = nil
|
39
|
+
# return eval("set_or_return key_type, method_symbol.to_s.camelcase, *args, &blk")
|
40
|
+
return set_or_return key_type, method_symbol.to_s.camelcase, *args, &blk
|
41
|
+
else
|
42
|
+
raise "Unrecognized key for class: #{self.class.inspect}. Tried to set_or_return #{method_symbol.inspect}, with: #{args.inspect}"
|
43
|
+
end
|
44
|
+
# puts "bob"
|
31
45
|
end
|
32
46
|
|
33
47
|
def validate_value key_type, key, value
|
@@ -53,7 +67,7 @@ module Plist4r
|
|
53
67
|
end
|
54
68
|
|
55
69
|
def set_or_return key_type, key, value=nil
|
56
|
-
puts "#{method_name}, key_type: #{key_type.inspect}, value: #{value.inspect}"
|
70
|
+
# puts "#{method_name}, key_type: #{key_type.inspect}, key: #{key.inspect}, value: #{value.inspect}"
|
57
71
|
if value
|
58
72
|
validate_value key_type, key, value unless key_type == nil
|
59
73
|
@hash[key] = value
|
@@ -62,4 +76,8 @@ module Plist4r
|
|
62
76
|
end
|
63
77
|
end
|
64
78
|
end
|
65
|
-
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
|
data/lib/plist4r/plist.rb
CHANGED
@@ -8,14 +8,16 @@ require 'plist4r/backend'
|
|
8
8
|
|
9
9
|
module Plist4r
|
10
10
|
class Plist
|
11
|
-
PlistOptionsHash = %w[
|
11
|
+
PlistOptionsHash = %w[filename path file_format plist_type unsupported_keys backends from_string]
|
12
12
|
FileFormats = %w[binary xml next_step]
|
13
13
|
|
14
14
|
def initialize *args, &blk
|
15
15
|
@hash = ::ActiveSupport::OrderedHash.new
|
16
|
-
|
16
|
+
@plist_type = plist_type :plist
|
17
|
+
|
17
18
|
@unsupported_keys = Config[:unsupported_keys]
|
18
19
|
@backends = Config[:backends]
|
20
|
+
|
19
21
|
@from_string = nil
|
20
22
|
@filename = nil
|
21
23
|
@file_format = nil
|
@@ -32,19 +34,20 @@ module Plist4r
|
|
32
34
|
raise "Unrecognized first argument: #{args.first.inspect}"
|
33
35
|
end
|
34
36
|
|
35
|
-
@plist_cache
|
37
|
+
@plist_cache ||= PlistCache.new self
|
36
38
|
end
|
37
39
|
|
38
40
|
def from_string string=nil
|
39
41
|
case string
|
40
42
|
when String
|
41
|
-
plist_format = ::Plist4r.string_detect_format
|
43
|
+
plist_format = ::Plist4r.string_detect_format(string)
|
42
44
|
if plist_format
|
43
|
-
|
45
|
+
@from_string = string
|
46
|
+
@plist_cache ||= PlistCache.new self
|
47
|
+
@plist_cache.from_string
|
44
48
|
else
|
45
49
|
raise "Unknown plist format for string: #{string}"
|
46
50
|
end
|
47
|
-
@from_string = string
|
48
51
|
when nil
|
49
52
|
@from_string
|
50
53
|
else
|
@@ -101,25 +104,63 @@ module Plist4r
|
|
101
104
|
end
|
102
105
|
end
|
103
106
|
|
107
|
+
def detect_plist_type
|
108
|
+
stat_m = {}
|
109
|
+
stat_r = {}
|
110
|
+
Config[:types].each do |t|
|
111
|
+
case t
|
112
|
+
when String, Symbol
|
113
|
+
t = eval "::Plist4r::PlistType::#{t.to_s.camelcase}"
|
114
|
+
when Class
|
115
|
+
t = t
|
116
|
+
else
|
117
|
+
raise "Unrecognized plist type: #{t.inspect}"
|
118
|
+
end
|
119
|
+
t_sym = t.to_s.gsub(/.*:/,"").snake_case.to_sym
|
120
|
+
stat_t = t.match_stat @hash.keys
|
121
|
+
|
122
|
+
stat_m.store stat_t[:matches], t_sym
|
123
|
+
stat_r.store stat_t[:ratio], t_sym
|
124
|
+
end
|
125
|
+
|
126
|
+
most_matches = stat_m.keys.sort.last
|
127
|
+
if most_matches == 0
|
128
|
+
plist_type :plist
|
129
|
+
elsif stat_m.keys.select{ |m| m == most_matches }.size > 1
|
130
|
+
most_matches = stat_r.keys.sort.last
|
131
|
+
if stat_r.keys.select{ |m| m == most_matches }.size > 1
|
132
|
+
plist_type :plist
|
133
|
+
else
|
134
|
+
plist_type stat_r[most_matches]
|
135
|
+
end
|
136
|
+
else
|
137
|
+
plist_type stat_m[most_matches]
|
138
|
+
end
|
139
|
+
return true
|
140
|
+
end
|
141
|
+
|
104
142
|
def plist_type plist_type=nil
|
105
143
|
begin
|
106
144
|
case plist_type
|
107
145
|
when Class
|
108
|
-
|
146
|
+
unless plist_type.is_a? ::Plist4r::PlistType
|
147
|
+
raise "Unrecognized Plist type. Class #{plist_type.inspect} isnt inherited from ::Plist4r::PlistType"
|
148
|
+
end
|
109
149
|
when Symbol, String
|
110
|
-
eval "
|
111
|
-
@plist_type = pt_klass.new :hash => @hash
|
150
|
+
plist_type = eval "::Plist4r::PlistType::#{plist_type.to_s.camelcase}"
|
112
151
|
when nil
|
113
|
-
@plist_type
|
152
|
+
return @plist_type.to_sym
|
114
153
|
else
|
115
154
|
raise "Please specify a valid plist class name, eg ::Plist4r::PlistType::ClassName, \"class_name\" or :class_name"
|
116
155
|
end
|
156
|
+
@plist_type = plist_type.new self
|
157
|
+
return @plist_type.to_sym
|
117
158
|
rescue
|
118
159
|
raise "Please specify a valid plist class name, eg ::Plist4r::PlistType::ClassName, \"class_name\" or :class_name"
|
119
160
|
end
|
120
161
|
end
|
121
|
-
|
122
|
-
def unsupported_keys bool
|
162
|
+
|
163
|
+
def unsupported_keys bool=nil
|
123
164
|
case bool
|
124
165
|
when true,false
|
125
166
|
@unsupported_keys = bool
|
@@ -143,14 +184,16 @@ module Plist4r
|
|
143
184
|
|
144
185
|
def parse_opts opts
|
145
186
|
PlistOptionsHash.each do |opt|
|
146
|
-
|
187
|
+
if opts[opt.to_sym]
|
188
|
+
value = opts[opt.to_sym]
|
189
|
+
eval "self.#{opt}(value)"
|
190
|
+
end
|
147
191
|
end
|
148
192
|
end
|
149
193
|
|
150
194
|
def open filename=nil
|
151
195
|
@filename = filename if filename
|
152
196
|
raise "No filename specified" unless @filename
|
153
|
-
# @hash = @plist_cache.open
|
154
197
|
@plist_cache.open
|
155
198
|
end
|
156
199
|
|
@@ -159,7 +202,10 @@ module Plist4r
|
|
159
202
|
end
|
160
203
|
|
161
204
|
def edit *args, &blk
|
162
|
-
|
205
|
+
@plist_type.hash @hash
|
206
|
+
instance_eval *args, &blk
|
207
|
+
detect_plist_type
|
208
|
+
@plist_cache.update_checksum
|
163
209
|
end
|
164
210
|
|
165
211
|
def method_missing method_sym, *args, &blk
|
@@ -227,37 +273,24 @@ module Plist4r
|
|
227
273
|
instance_eval(&@block) if @block
|
228
274
|
end
|
229
275
|
|
276
|
+
def override_plist_keys?
|
277
|
+
return true unless @label == @filename.match(/^.*\/(.*)\.plist$/)[1]
|
278
|
+
vars = self.instance_variables - ["@filename","@label","@shortname","@block","@hash","@obj"]
|
279
|
+
return true unless vars.empty?
|
280
|
+
end
|
281
|
+
|
230
282
|
def finalize
|
231
283
|
if File.exists? @filename
|
232
284
|
if override_plist_keys?
|
233
285
|
# @hash = @obj = ::LibxmlLaunchdPlistParser.new(@filename).plist_struct
|
234
286
|
# eval_plist_block(&@block) if @block
|
235
|
-
write_plist
|
287
|
+
# write_plist
|
236
288
|
end
|
237
289
|
else
|
238
|
-
write_plist
|
290
|
+
# write_plist
|
239
291
|
end
|
240
|
-
|
241
|
-
end
|
242
|
-
|
243
|
-
def override_plist_keys?
|
244
|
-
return true unless @label == @filename.match(/^.*\/(.*)\.plist$/)[1]
|
245
|
-
vars = self.instance_variables - ["@filename","@label","@shortname","@block","@hash","@obj"]
|
246
|
-
return true unless vars.empty?
|
247
|
-
end
|
248
|
-
|
249
|
-
def write_plist
|
250
|
-
require 'haml'
|
251
|
-
engine = Haml::Engine.new File.read("launchd_plist.haml")
|
252
|
-
rendered_xml_output = engine.render self
|
253
|
-
File.open(@filename,'w') do |o|
|
254
|
-
o << rendered_xml_output
|
255
|
-
end
|
256
|
-
|
257
|
-
end
|
258
|
-
|
259
|
-
def validate
|
260
|
-
system "/usr/bin/plutil #{@filename}"
|
261
|
-
end
|
292
|
+
end
|
262
293
|
end
|
263
294
|
end
|
295
|
+
|
296
|
+
|
data/lib/plist4r/plist_cache.rb
CHANGED
@@ -23,19 +23,25 @@ module Plist4r
|
|
23
23
|
checksum != last_checksum
|
24
24
|
end
|
25
25
|
|
26
|
+
def from_string
|
27
|
+
@backend.call :from_string
|
28
|
+
update_checksum
|
29
|
+
@plist.detect_plist_type
|
30
|
+
@plist
|
31
|
+
end
|
32
|
+
|
26
33
|
def to_xml
|
27
|
-
|
28
|
-
# if needs_update
|
34
|
+
if needs_update || @xml.nil?
|
29
35
|
puts "needs update"
|
30
36
|
update_checksum
|
31
37
|
@xml = @backend.call :to_xml
|
32
|
-
|
33
|
-
|
34
|
-
|
38
|
+
else
|
39
|
+
@xml
|
40
|
+
end
|
35
41
|
end
|
36
42
|
|
37
43
|
def to_binary
|
38
|
-
if needs_update
|
44
|
+
if needs_update || @binary.nil?
|
39
45
|
update_checksum
|
40
46
|
@binary = @backend.call :to_binary
|
41
47
|
else
|
@@ -44,7 +50,7 @@ module Plist4r
|
|
44
50
|
end
|
45
51
|
|
46
52
|
def to_next_step
|
47
|
-
if needs_update
|
53
|
+
if needs_update || @next_step.nil?
|
48
54
|
update_checksum
|
49
55
|
@next_step = @backend.call :to_next_step
|
50
56
|
else
|
@@ -55,6 +61,7 @@ module Plist4r
|
|
55
61
|
def open
|
56
62
|
@backend.call :open
|
57
63
|
update_checksum
|
64
|
+
@plist.detect_plist_type
|
58
65
|
@plist
|
59
66
|
end
|
60
67
|
|
data/lib/plist4r/plist_type.rb
CHANGED
@@ -5,9 +5,43 @@ module Plist4r
|
|
5
5
|
class PlistType
|
6
6
|
include ::Plist4r::DataMethods
|
7
7
|
|
8
|
-
def initialize
|
9
|
-
|
10
|
-
@hash = @orig =
|
8
|
+
def initialize plist, *args, &blk
|
9
|
+
@plist = plist
|
10
|
+
@hash = @orig = plist.to_hash
|
11
|
+
end
|
12
|
+
|
13
|
+
def hash hash=nil
|
14
|
+
case hash
|
15
|
+
when ::ActiveSupport::OrderedHash
|
16
|
+
@hash = @orig = hash
|
17
|
+
when nil
|
18
|
+
@hash
|
19
|
+
else
|
20
|
+
raise "Must hash be an ::ActiveSupport::OrderedHash"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.valid_keys
|
25
|
+
raise "Method not implemented #{method_name.to_sym.inspect}, for class #{self.inspect}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def valid_keys
|
29
|
+
self.class.valid_keys
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.match_stat plist_keys
|
33
|
+
type_keys = valid_keys.values.flatten
|
34
|
+
matches = plist_keys & type_keys
|
35
|
+
include_ratio = matches.size.to_f / type_keys.size
|
36
|
+
return :matches => matches.size, :ratio => include_ratio
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
return @string ||= self.class.to_s.gsub(/.*:/,"").snake_case
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_sym
|
44
|
+
return @sym ||= to_s.to_sym
|
11
45
|
end
|
12
46
|
end
|
13
47
|
|
@@ -4,16 +4,15 @@ require 'plist4r/plist_type'
|
|
4
4
|
module Plist4r
|
5
5
|
class PlistType::Launchd < PlistType
|
6
6
|
|
7
|
-
def valid_keys
|
7
|
+
def self.valid_keys
|
8
8
|
{
|
9
9
|
:string => %w[Label UserName GroupName LimitLoadToSessionType Program RootDirectory WorkingDirectory StandardInPath StandardOutPath StandardErrorPath],
|
10
10
|
:bool => %w[Disabled EnableGlobbing EnableTransactions OnDemand RunAtLoad InitGroups StartOnMount Debug WaitForDebugger AbandonProcessGroup HopefullyExitsFirst HopefullyExitsLast LowPriorityIO LaunchOnlyOnce],
|
11
11
|
:integer => %w[Umask TimeOut ExitTimeOut ThrottleInterval StartInterval Nice],
|
12
12
|
:array_of_strings => %w[LimitLoadToHosts LimitLoadFromHosts ProgramArguments WatchPaths QueueDirectories],
|
13
|
-
:
|
13
|
+
:method_defined => %w[inetdCompatibility KeepAlive EnvironmentVariables StartCalendarInterval SoftResourceLimits, HardResourceLimits MachServices Sockets]
|
14
14
|
}
|
15
15
|
end
|
16
|
-
|
17
16
|
|
18
17
|
# :call-seq:
|
19
18
|
# inetdCompatibility({:wait => true})
|
data/plist4r.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{plist4r}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["dreamcat4"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-18}
|
13
13
|
s.description = %q{In development. Plist4R is a gem which is striving for 3 things: ease of use, speed, and reliability handling of plists. To help achieve these goals, we may plug-in or re-write this gem with one or several backends. Notably, we try to distinguish this gem by providing easy-to use DSL interface for users. For common plist type(s), such as convenience methods for Launchd Plist}
|
14
14
|
s.email = %q{dreamcat4@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -49,11 +49,10 @@ Gem::Specification.new do |s|
|
|
49
49
|
"lib/plist4r/plist_type/launchd.rb",
|
50
50
|
"lib/plist4r/plist_type/plist.rb",
|
51
51
|
"plist4r.gemspec",
|
52
|
-
"plists/
|
53
|
-
"plists/
|
54
|
-
"plists/
|
55
|
-
"plists/
|
56
|
-
"plists/test.plist",
|
52
|
+
"plists/example_big_binary.plist",
|
53
|
+
"plists/example_medium_binary_launchd.plist",
|
54
|
+
"plists/example_medium_launchd.xml",
|
55
|
+
"plists/mini.xml",
|
57
56
|
"spec/examples.rb",
|
58
57
|
"spec/plist4r/plist_spec.rb",
|
59
58
|
"spec/plist4r_spec.rb",
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/test.rb
CHANGED
@@ -2,13 +2,38 @@
|
|
2
2
|
|
3
3
|
require 'lib/plist4r'
|
4
4
|
|
5
|
-
|
5
|
+
# puts "Backends = #{::Plist4r::Config[:backends].inspect}"
|
6
6
|
# Plist4r.new
|
7
7
|
|
8
|
-
p = Plist4r.open "plists/
|
8
|
+
p = Plist4r.open "plists/mini.xml"
|
9
9
|
|
10
10
|
# puts p.inspect
|
11
11
|
# puts p.to_hash.inspect
|
12
|
+
# puts p.to_xml
|
13
|
+
|
14
|
+
# b = p.to_binary
|
15
|
+
# puts b.inspect
|
16
|
+
|
17
|
+
|
18
|
+
# p2 = b.to_plist
|
19
|
+
# puts p2.inspect
|
20
|
+
# puts p2.to_xml
|
21
|
+
|
22
|
+
# puts p2.to_xml
|
23
|
+
# puts "plist type is"
|
24
|
+
# puts p2.plist_type.inspect
|
25
|
+
|
26
|
+
# p2.unsupported_keys false
|
27
|
+
# puts p2.unsupported_keys.inspect
|
28
|
+
# p2.<< do
|
29
|
+
# somekey "append"
|
30
|
+
# end
|
31
|
+
|
32
|
+
# puts p2.to_hash.inspect
|
33
|
+
# puts p2.to_xml
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
12
38
|
|
13
|
-
puts p.to_xml
|
14
39
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plist4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dreamcat4
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-03-
|
12
|
+
date: 2010-03-18 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -84,11 +84,10 @@ files:
|
|
84
84
|
- lib/plist4r/plist_type/launchd.rb
|
85
85
|
- lib/plist4r/plist_type/plist.rb
|
86
86
|
- plist4r.gemspec
|
87
|
-
- plists/
|
88
|
-
- plists/
|
89
|
-
- plists/
|
90
|
-
- plists/
|
91
|
-
- plists/test.plist
|
87
|
+
- plists/example_big_binary.plist
|
88
|
+
- plists/example_medium_binary_launchd.plist
|
89
|
+
- plists/example_medium_launchd.xml
|
90
|
+
- plists/mini.xml
|
92
91
|
- spec/examples.rb
|
93
92
|
- spec/plist4r/plist_spec.rb
|
94
93
|
- spec/plist4r_spec.rb
|
@@ -1,75 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
-
<plist version="1.0">
|
4
|
-
<dict>
|
5
|
-
<key>autoPoll</key>
|
6
|
-
<true/>
|
7
|
-
<key>cMax</key>
|
8
|
-
<integer>129600</integer>
|
9
|
-
<key>debug</key>
|
10
|
-
<true/>
|
11
|
-
<key>debugInXcode</key>
|
12
|
-
<false/>
|
13
|
-
<key>desktopPrefs</key>
|
14
|
-
<dict>
|
15
|
-
<key>BackgroundColor</key>
|
16
|
-
<array>
|
17
|
-
<real>0.254902</real>
|
18
|
-
<real>0.4117647</real>
|
19
|
-
<real>0.6666667</real>
|
20
|
-
</array>
|
21
|
-
<key>Change</key>
|
22
|
-
<string>Never</string>
|
23
|
-
<key>ChangePath</key>
|
24
|
-
<string>/Library/Desktop Pictures/Nature</string>
|
25
|
-
<key>ChangeTime</key>
|
26
|
-
<real>1800</real>
|
27
|
-
<key>DrawBackgroundColor</key>
|
28
|
-
<true/>
|
29
|
-
<key>ImageFileAlias</key>
|
30
|
-
<data>AAAAAAC4AAMAAAAAxY+tngAASCsAAAAAAEh7KwBIe0wAAMaUOpUAAAAACSD//gAAAAAAAAAA/////wABAAwASHsrAEh61QBGMgwADgAUAAkARQBhAHIAdABoAC4AagBwAGcADwAaAAwATQBhAGMAaQBuAHQAbwBzAGgAIABIAEQAEgApTGlicmFyeS9EZXNrdG9wIFBpY3R1cmVzL05hdHVyZS9FYXJ0aC5qcGcAABMAAS8A//8AAA==</data>
|
31
|
-
<key>ImageFilePath</key>
|
32
|
-
<string>/Library/Desktop Pictures/Nature/Earth.jpg</string>
|
33
|
-
<key>NewChangePath</key>
|
34
|
-
<string>/Library/Desktop Pictures/Nature</string>
|
35
|
-
<key>NewImageFilePath</key>
|
36
|
-
<string>/Library/Desktop Pictures/Nature/Earth.jpg</string>
|
37
|
-
<key>Placement</key>
|
38
|
-
<string>Crop</string>
|
39
|
-
<key>Random</key>
|
40
|
-
<false/>
|
41
|
-
</dict>
|
42
|
-
<key>error</key>
|
43
|
-
<data>YnBsaXN0MDDUAQIDBAUIT1BUJHRvcFgkb2JqZWN0c1gkdmVyc2lvblkkYXJjaGl2ZXLRBgdUcm9vdIABrxAUCQoTFCIjJCUmJy00NTo7RUZHSEtVJG51bGzUCwwNDg8QERJWJGNsYXNzVk5TQ29kZVpOU1VzZXJJbmZvWE5TRG9tYWlugBMT/////////BeAA4ACXxAQTlNVUkxFcnJvckRvbWFpbtMVFgsXHCFaTlMub2JqZWN0c1dOUy5rZXlzpBgZGhuACIAJgAuADKQdHh8ggASABYAGgAeAEl8QGk5TRXJyb3JGYWlsaW5nVVJMU3RyaW5nS2V5XxAUTlNFcnJvckZhaWxpbmdVUkxLZXlfEBZOU0xvY2FsaXplZERlc2NyaXB0aW9uXxARTlNVbmRlcmx5aW5nRXJyb3JfEJFodHRwOi8vcGhvdG9ncmFwaHkubmF0aW9uYWxnZW9ncmFwaGljLmNvbS9zdGF0aWNmaWxlcy9OR1MvU2hhcmVkL1N0YXRpY0ZpbGVzL1Bob3RvZ3JhcGh5L0ltYWdlcy9QT0QvYS9hdG9tLWJvbWItYmlraW5pLWF0b2xsLTYzMzE3OC0xMDA1MDkteGwuanBn0ygpCyoYLFdOUy5iYXNlW05TLnJlbGF0aXZlgACACIAK0i4vMDNYJGNsYXNzZXNaJGNsYXNzbmFtZaIxMlVOU1VSTFhOU09iamVjdFVOU1VSTF8QFlRoZSByZXF1ZXN0IHRpbWVkIG91dC7UCwwNDg83ODmAExP////////8F4AOgA1fEBdrQ0ZFcnJvckRvbWFpbkNGTmV0d29ya9MVFgs8QCGjGRgagAmACIALo0FCQ4APgBCAEYASXxAUTlNFcnJvckZhaWxpbmdVUkxLZXlfEBpOU0Vycm9yRmFpbGluZ1VSTFN0cmluZ0tleV8QFk5TTG9jYWxpemVkRGVzY3JpcHRpb27SLi9JSqJKMlxOU0RpY3Rpb25hcnnSLi9MTqJNMldOU0Vycm9yV05TRXJyb3ISAAGGoF8QD05TS2V5ZWRBcmNoaXZlcgAIABEAFgAfACgAMgA1ADoAPABTAFkAYgBpAHAAewCEAIYAjwCRAJMApgCtALgAwADFAMcAyQDLAM0A0gDUANYA2ADaANwA+QEQASkBPQHRAdgB4AHsAe4B8AHyAfcCAAILAg4CFAIdAiMCPAJFAkcCUAJSAlQCbgJ1AnkCewJ9An8CgwKFAocCiQKLAqICvwLYAt0C4ALtAvIC9QL9AwUDCgAAAAAAAAIBAAAAAAAAAFEAAAAAAAAAAAAAAAAAAAMc</data>
|
44
|
-
<key>filename</key>
|
45
|
-
<string></string>
|
46
|
-
<key>frequency</key>
|
47
|
-
<string>daily</string>
|
48
|
-
<key>hMin</key>
|
49
|
-
<integer>240</integer>
|
50
|
-
<key>ignoreLostConnectivity</key>
|
51
|
-
<false/>
|
52
|
-
<key>imageSource</key>
|
53
|
-
<data>YnBsaXN0MDDUAQIDBAUI2ttUJHRvcFgkb2JqZWN0c1gkdmVyc2lvblkkYXJjaGl2ZXLRBgdUcm9vdIABrxAwCQofICElLC0uNjlBSktMVFlhYmVocHR5eoKGi4ycnZ6foKGnqKyytbm/wMTIzNDVVSRudWxs2gsMDQ4PEBESExQVFhcYGRoYHB0cWGRhdGFGaWxlU3VpZFV0aXRsZVdkYXRhVXJsW2Rlc2NyaXB0aW9uXxAPX29iakluaXRpYWxpemVkWGltYWdlVXJsVXF1ZXJ5ViRjbGFzc1VlcnJvcoADgASAB4ACgAiABoACgACAL4AAXxCRaHR0cDovL3Bob3RvZ3JhcGh5Lm5hdGlvbmFsZ2VvZ3JhcGhpYy5jb20vc3RhdGljZmlsZXMvTkdTL1NoYXJlZC9TdGF0aWNGaWxlcy9QaG90b2dyYXBoeS9JbWFnZXMvUE9EL2EvYXRvbS1ib21iLWJpa2luaS1hdG9sbC02MzMxNzgtMTAwNTA5LXhsLmpwZ18QaC9Vc2Vycy9pZC9QaWN0dXJlIG9mIFRvZGF5L3Rlc3QvcGljdHVyZXMvTmF0aW9uYWwgR2VvZ3JhcGhpYy9hdG9tLWJvbWItYmlraW5pLWF0b2xsLTYzMzE3OC0xMDA1MDkteGwuanBn0iITIyRZTlMuc3RyaW5nXxAoYWJlODJhYmFmY2I2NTM1NzQwNzIxODFlYzMxYzQwMDRjZDBiZjc4YYAF0iYnKClYJGNsYXNzZXNaJGNsYXNzbmFtZaMpKitfEA9OU011dGFibGVTdHJpbmdYTlNTdHJpbmdYTlNPYmplY3QJbxBVAEEAdABvAG0AaQBjACAAQgBvAG0AYgAgAFQAZQBzAHQAIABQAGgAbwB0AG8ALAAgAEIAaQBrAGkAbgBpACAAQQB0AG8AbABsACAAVwBhAGwAbABwAGEAcABlAHIAICATACAATgBhAHQAaQBvAG4AYQBsACAARwBlAG8AZwByAGEAcABoAGkAYwAgAFAAaABvAHQAbwAgAG8AZgAgAHQAaABlACAARABhAHnULzATMTIzNDVfEA9OU0F0dHJpYnV0ZUluZm9cTlNBdHRyaWJ1dGVzWE5TU3RyaW5ngCyACoAugAnSIhM3JF8RAURBdG9tIEJvbWIgVGVzdCwgQmlraW5pIEF0b2xsClBob3RvZ3JhcGggYnkgVS5TLiBOYXZ5ClRoaXMgbW9udGggaW4gUGhvdG8gb2YgdGhlIERheTogSW1hZ2VzIEZyb20gdGhlIE5hdGlvbmFsIEdlb2dyYXBoaWMgQXJjaGl2ZQpUaGUgc2Vjb25kIGF0b21pYyBib21iIHRlc3RlZCBpbiBPcGVyYXRpb24gQ3Jvc3Nyb2FkcwoKRnJvbSB0aGUgdXBjb21pbmcgTmF0aW9uYWwgR2VvZ3JhcGhpYyBib29rIFRoZSBJbWFnZSBDb2xsZWN0aW9uLCBkdWUgZmFsbCAyMDA5LiBTaG9wIGZvciBvdGhlciBwaG90b2dyYXBoeSBib29rcyBmcm9tIE5hdGlvbmFsIEdlb2dyYXBoaWMuCgqABdI6EztAWk5TLm9iamVjdHOkPD0+P4ALgBSAGIAcgCvTOkITQ0ZJV05TLmtleXOiREWADoAQokdIgAyADYATXxAQTlNQYXJhZ3JhcGhTdHlsZVZOU0ZvbnTUTU5PE1AcUlNfEBJOU1BhcmFncmFwaFNwYWNpbmdaTlNUYWJTdG9wc1tOU0FsaWdubWVudCNAGAAAAAAAAIAAEASAD9ImJ1VYo1ZXK18QF05TTXV0YWJsZVBhcmFncmFwaFN0eWxlXxAQTlNQYXJhZ3JhcGhTdHlsZV8QF05TTXV0YWJsZVBhcmFncmFwaFN0eWxl1FpbE1xdXl9gVk5TU2l6ZVZOU05hbWVYTlNmRmxhZ3MjQDYAAAAAAACAEYASEBBfEBFMdWNpZGFHcmFuZGUtQm9sZNImJ2NkomQrVk5TRm9udNImJ2ZnomcrXE5TRGljdGlvbmFyedM6QhNpbEmiamuAFYAWokdIgAyADYAT1E1OTxNxHFJTI0AYAAAAAAAAgACAD9RaWxNcdXZfeCNAJgAAAAAAAIAXgBIQEFxMdWNpZGFHcmFuZGXTOkITe35Jonx9gBmAGqJHSIAMgA2AE9RNTk8TgxxSUyNAGAAAAAAAAIAAgA/UWlsTXIeIX4ojQCYAAAAAAACAG4ASEBBfEBFIZWx2ZXRpY2EtT2JsaXF1ZdM6QhONlEmmjo9rkZKTgCGAIoAWgCWAJ4AoppWWSJhHmoAdgB6ADYAfgAyAIIATW05TVW5kZXJsaW5lVk5TTGlua1dOU0NvbG9yWE5TQ3Vyc29yEAHToqMTHKWmV05TLmJhc2VbTlMucmVsYXRpdmWAAIAjgCRfEG9odHRwOi8vc2hvcC5uYXRpb25hbGdlb2dyYXBoaWMuY29tL2NvdXBvbi5qc3A/Y29kZT1NUjIwMjEyJlVSTD0lMkZqdW1wLmpzcCUzRml0ZW1JRCUzRDQ0NDUlMjZpdGVtVHlwZSUzRFBST0RVQ1TSJiepq6KqK1VOU1VSTFVOU1VSTNOtrhOvsLFVTlNSR0JcTlNDb2xvclNwYWNlTxARMCAwIDAuOTMzMzMzMzM3MwAQAoAm0iYns7SitCtXTlNDb2xvctRNTk8TthxSUyNAGAAAAAAAAIAAgA/TursTvL2+WU5TSG90U3BvdFxOU0N1cnNvclR5cGWAKRAMgCpXezgsIC04fdImJ8HDosIrWE5TQ3Vyc29yWE5TQ3Vyc29y0iYnxcajxscrXk5TTXV0YWJsZUFycmF5V05TQXJyYXnSyRPKy1dOUy5kYXRhTxAQHQAYAUsCYwEUAiABEQMcAYAt0iYnzc6jzs8rXU5TTXV0YWJsZURhdGFWTlNEYXRh0iYn0dSj0tMrXxAZTlNNdXRhYmxlQXR0cmlidXRlZFN0cmluZ18QEk5TQXR0cmlidXRlZFN0cmluZ18QGU5TTXV0YWJsZUF0dHJpYnV0ZWRTdHJpbmfSJifW2aPX2CtdUFRJbWFnZVNvdXJjZVtMT1dlYlNvdXJjZV1QVEltYWdlU291cmNlEgABhqBfEA9OU0tleWVkQXJjaGl2ZXIACAARABYAHwAoADIANQA6ADwAbwB1AIoAkwCXAJ0ApQCxAMMAzADSANkA3wDhAOMA5QDnAOkA6wDtAO8A8QDzAYcB8gH3AgECLAIuAjMCPAJHAksCXQJmAm8CcAMdAyYDOANFA04DUANSA1QDVgNbBKMEpQSqBLUEugS8BL4EwATCBMQEywTTBNYE2ATaBN0E3wThBOME9gT9BQYFGwUmBTIFOwU9BT8FQQVGBUoFZAV3BZEFmgWhBagFsQW6BbwFvgXABdQF2QXcBeMF6AXrBfgF/wYCBgQGBgYJBgsGDQYPBhgGIQYjBiUGLgY3BjkGOwY9BkoGUQZUBlYGWAZbBl0GXwZhBmoGcwZ1BncGgAaJBosGjQaPBqMGqgaxBrMGtQa3BrkGuwa9BsQGxgbIBsoGzAbOBtAG0gbeBuUG7Qb2BvgG/wcHBxMHFQcXBxkHiweQB5MHmQefB6YHrAe5B80HzwfRB9YH2QfhB+oH8wf1B/cH/ggICBUIFwgZCBsIIwgoCCsINAg9CEIIRghVCF0IYghqCH0IfwiECIgIlgidCKIIpgjCCNcI8wj4CPwJCgkWCSQJKQAAAAAAAAIBAAAAAAAAANwAAAAAAAAAAAAAAAAAAAk7</data>
|
54
|
-
<key>lastUpdate</key>
|
55
|
-
<date>2009-10-05T16:37:47Z</date>
|
56
|
-
<key>maxPictures</key>
|
57
|
-
<integer>1</integer>
|
58
|
-
<key>nextDueDate</key>
|
59
|
-
<date>2009-10-05T22:45:00Z</date>
|
60
|
-
<key>pollingInterval</key>
|
61
|
-
<integer>28799</integer>
|
62
|
-
<key>previousPolls</key>
|
63
|
-
<integer>2</integer>
|
64
|
-
<key>ptEnabled</key>
|
65
|
-
<false/>
|
66
|
-
<key>savePath</key>
|
67
|
-
<string>~/Picture of Today/test/pictures/National Geographic</string>
|
68
|
-
<key>selectedSource</key>
|
69
|
-
<integer>4</integer>
|
70
|
-
<key>updateInterval</key>
|
71
|
-
<integer>86400</integer>
|
72
|
-
<key>updateTime</key>
|
73
|
-
<date>2000-01-01T23:45:00Z</date>
|
74
|
-
</dict>
|
75
|
-
</plist>
|