r18n-core 0.4 → 0.4.1
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/ChangeLog +6 -1
- data/README.rdoc +3 -2
- data/base/cs.yml +2 -2
- data/base/de.yml +3 -3
- data/base/en.yml +2 -2
- data/base/eo.yml +2 -2
- data/base/es.yml +2 -2
- data/base/fr.yml +2 -2
- data/base/it.yml +2 -2
- data/base/kk.yml +2 -2
- data/base/pl.yml +2 -2
- data/base/pt_br.yml +2 -2
- data/base/ru.yml +2 -2
- data/base/zh.yml +2 -2
- data/lib/r18n-core/filters.rb +86 -61
- data/lib/r18n-core/translated.rb +4 -2
- data/lib/r18n-core/translation.rb +11 -7
- data/lib/r18n-core/untranslated.rb +1 -1
- data/lib/r18n-core/version.rb +1 -1
- data/lib/r18n-core/yaml_loader.rb +14 -1
- data/spec/filters_spec.rb +23 -5
- data/spec/translations/general/en.yml +0 -2
- data/spec/translations/general/ru.yml +2 -0
- data/spec/yaml_loader_spec.rb +2 -1
- metadata +2 -2
data/ChangeLog
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
== 0.4.1 (Lazy Boole)
|
2
|
+
* Add passive filters.
|
3
|
+
* Receive filter position as option Hash.
|
4
|
+
* Fix base translations (by Pavel Kunc).
|
5
|
+
|
1
6
|
== 0.4 (D-Day)
|
2
7
|
* Rails I18n compatibility.
|
3
8
|
* Rewrite a lot of core code to fast and cleanup version.
|
@@ -46,7 +51,7 @@
|
|
46
51
|
* Ruby 1.9 compatibility.
|
47
52
|
* Add German locale (by Benjamin Meichsner).
|
48
53
|
|
49
|
-
== 0.2 (Freedom of
|
54
|
+
== 0.2 (Freedom of Language)
|
50
55
|
* Locale class can be extended for special language (for example, Indian locale
|
51
56
|
may has another digits grouping).
|
52
57
|
* Load translations from several dirs.
|
data/README.rdoc
CHANGED
@@ -220,12 +220,13 @@ See <tt>base/</tt> in dir in gem.
|
|
220
220
|
=== Filters
|
221
221
|
|
222
222
|
You can also add you own filter for translations: escape HTML entries, convert
|
223
|
-
from Markdown syntax, etc.
|
223
|
+
from Markdown syntax, etc. Filters can be passive to process translation only on
|
224
|
+
loading.
|
224
225
|
|
225
226
|
R18n::Filters.add('custom_type', :filter_name) do |content, config, replace|
|
226
227
|
content.gsub(' ', replace)
|
227
228
|
end
|
228
|
-
R18n::Filters.add('custom_type') do |content, config
|
229
|
+
R18n::Filters.add('custom_type', :passive => true) do |content, config|
|
229
230
|
content + '!'
|
230
231
|
end
|
231
232
|
|
data/base/cs.yml
CHANGED
data/base/de.yml
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
ok: OK
|
2
2
|
save: Speichern
|
3
3
|
cancel: Abbrechen
|
4
|
-
yes: Ja
|
5
|
-
no: Nein
|
4
|
+
'yes': Ja
|
5
|
+
'no': Nein
|
6
6
|
exit: Ausgang
|
7
7
|
delete: Löschen
|
8
8
|
|
@@ -28,4 +28,4 @@ human_time:
|
|
28
28
|
yesterday: gestern
|
29
29
|
days_ago: !!pl
|
30
30
|
1: %1 Tag vor
|
31
|
-
n: %1 Tagen vor
|
31
|
+
n: %1 Tagen vor
|
data/base/en.yml
CHANGED
data/base/eo.yml
CHANGED
data/base/es.yml
CHANGED
data/base/fr.yml
CHANGED
data/base/it.yml
CHANGED
data/base/kk.yml
CHANGED
data/base/pl.yml
CHANGED
data/base/pt_br.yml
CHANGED
data/base/ru.yml
CHANGED
data/base/zh.yml
CHANGED
data/lib/r18n-core/filters.rb
CHANGED
@@ -30,12 +30,13 @@ module R18n
|
|
30
30
|
# This content will be processed by filter
|
31
31
|
#
|
32
32
|
# Filter function will be receive filtered content as first argument, struct
|
33
|
-
# with filter config as second and filter parameters as next arguments.
|
33
|
+
# with filter config as second and filter parameters as next arguments. You
|
34
|
+
# can set passive filter, which will process translation only on loading.
|
34
35
|
#
|
35
36
|
# R18n::Filters.add('custom_type', :no_space) do |content, config, replace|
|
36
37
|
# content.gsub(' ', replace)
|
37
38
|
# end
|
38
|
-
# R18n::Filters.add('custom_type') do |content, config
|
39
|
+
# R18n::Filters.add('custom_type', :passive => true) do |content, config|
|
39
40
|
# content + '!'
|
40
41
|
# end
|
41
42
|
#
|
@@ -48,7 +49,7 @@ module R18n
|
|
48
49
|
# end
|
49
50
|
#
|
50
51
|
# Filter config contain two parameters: translation locale and path. But it is
|
51
|
-
#
|
52
|
+
# Hash and you can add you own parameter to cross-filter communications:
|
52
53
|
#
|
53
54
|
# R18n::Filters.add(String, :hide_truth) do |content, config|
|
54
55
|
# return content if config[:censorship_check]
|
@@ -73,67 +74,82 @@ module R18n
|
|
73
74
|
# i18n.filtered('_') #=> "This_content_will_be_processed_by_filter!"
|
74
75
|
# R18n::Filters.delete(:no_space)
|
75
76
|
module Filters
|
76
|
-
Filter = Struct.new(:name, :type, :block, :enabled) do
|
77
|
-
def call(*params)
|
78
|
-
block.call(*params)
|
79
|
-
end
|
80
|
-
|
81
|
-
def enabled?
|
82
|
-
enabled
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
77
|
class << self
|
87
78
|
# Hash of filter names to Filters.
|
88
|
-
|
89
|
-
@defined ||= {}
|
90
|
-
end
|
91
|
-
|
92
|
-
# Hash of types to enabled Filters.
|
93
|
-
def enabled
|
94
|
-
@enabled ||= Hash.new([])
|
95
|
-
end
|
79
|
+
attr_accessor :defined
|
96
80
|
|
97
81
|
# Hash of types to all Filters.
|
98
|
-
|
99
|
-
|
100
|
-
|
82
|
+
attr_accessor :by_type
|
83
|
+
|
84
|
+
# Hash of types to enabled active filters.
|
85
|
+
attr_accessor :active_enabled
|
101
86
|
|
102
|
-
#
|
103
|
-
|
87
|
+
# Hash of types to enabled passive filters.
|
88
|
+
attr_accessor :passive_enabled
|
89
|
+
|
90
|
+
# Hash of types to enabled passive and active filters.
|
91
|
+
attr_accessor :enabled
|
92
|
+
|
93
|
+
# Process +value+ by filters in +enabled+.
|
94
|
+
def process(enabled, type, value, locale, path, params)
|
104
95
|
config = { :locale => locale, :path => path }
|
105
96
|
|
106
|
-
|
97
|
+
enabled[type].each do |filter|
|
98
|
+
value = filter.call(value, config, *params)
|
99
|
+
end
|
107
100
|
|
108
101
|
if value.is_a? String
|
109
102
|
value = TranslatedString.new(value, locale, path)
|
110
|
-
process_string(value, config, params)
|
103
|
+
process_string(enabled, value, config, params)
|
111
104
|
else
|
112
105
|
value
|
113
106
|
end
|
114
107
|
end
|
115
108
|
|
116
|
-
# Process +value+ by global filters
|
117
|
-
def process_string(value, config, params)
|
109
|
+
# Process +value+ by global filters in +enabled+.
|
110
|
+
def process_string(enabled, value, config, params)
|
118
111
|
if config.is_a? String
|
119
112
|
config = { :locale => value.locale, :path => config }
|
120
113
|
end
|
121
|
-
|
114
|
+
enabled[String].each do |f|
|
122
115
|
value = f.call(value, config, *params)
|
123
116
|
end
|
124
117
|
value
|
125
118
|
end
|
126
119
|
|
120
|
+
# Rebuild +active_enabled+ and +passive_enabled+ for +type+.
|
121
|
+
def rebuild_enabled!(type)
|
122
|
+
@passive_enabled[type] = []
|
123
|
+
@active_enabled[type] = []
|
124
|
+
@enabled[type] = []
|
125
|
+
|
126
|
+
@by_type[type].each do |filter|
|
127
|
+
if filter.enabled?
|
128
|
+
@enabled[type] << filter
|
129
|
+
if filter.passive?
|
130
|
+
@passive_enabled[type] << filter
|
131
|
+
else
|
132
|
+
@active_enabled[type] << filter
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
127
138
|
# Add new filter for +type+ with +name+ and return filter object. You
|
128
139
|
# can use String class as +type+ to add global filter for all translated
|
129
140
|
# string.
|
130
141
|
#
|
131
|
-
# Several filters for same type will be call consecutively, but you can
|
132
|
-
# set +position+ in call list.
|
133
|
-
#
|
134
142
|
# Filter content will be sent to +block+ as first argument, struct with
|
135
143
|
# config as second and filters parameters will be in next arguments.
|
136
|
-
|
144
|
+
#
|
145
|
+
# Options:
|
146
|
+
# * +position+ – change order on processing several filters for same type.
|
147
|
+
# Note that passive filters will be always run before active.
|
148
|
+
# * +passive+ – if +true+, filter will process only on translation
|
149
|
+
# loading. Note that you must add all passive before load translation.
|
150
|
+
def add(type, name = nil, options = {}, &block)
|
151
|
+
options, name = name, nil if name.is_a? Hash
|
152
|
+
|
137
153
|
unless name
|
138
154
|
@last_auto_name ||= 0
|
139
155
|
begin
|
@@ -144,52 +160,61 @@ module R18n
|
|
144
160
|
delete(name)
|
145
161
|
end
|
146
162
|
|
147
|
-
|
148
|
-
defined[name] = filter
|
163
|
+
@by_type[type] = [] unless @by_type.has_key? type
|
149
164
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
enabled[type].insert(position, filter)
|
156
|
-
by_type[type].insert(position, filter)
|
165
|
+
filter = Filter.new(name, type, block, true, options[:passive])
|
166
|
+
@defined[name] = filter
|
167
|
+
|
168
|
+
if options.has_key? :position
|
169
|
+
@by_type[type].insert(options[:position], filter)
|
157
170
|
else
|
158
|
-
|
159
|
-
by_type[type] << defined[name]
|
171
|
+
@by_type[type] << filter
|
160
172
|
end
|
173
|
+
rebuild_enabled! type
|
161
174
|
|
162
175
|
filter
|
163
176
|
end
|
164
177
|
|
165
178
|
# Delete +filter+ by name or Filter object.
|
166
179
|
def delete(filter)
|
167
|
-
filter = defined[filter] unless filter.is_a? Filter
|
180
|
+
filter = @defined[filter] unless filter.is_a? Filter
|
168
181
|
return unless filter
|
169
182
|
|
170
|
-
defined.delete(filter.name)
|
171
|
-
by_type[filter.type].delete(filter)
|
172
|
-
|
183
|
+
@defined.delete(filter.name)
|
184
|
+
@by_type[filter.type].delete(filter)
|
185
|
+
rebuild_enabled! filter.type
|
173
186
|
end
|
174
187
|
|
175
188
|
# Disable +filter+ by name or Filter object.
|
176
189
|
def off(filter)
|
177
|
-
filter = defined[filter] unless filter.is_a? Filter
|
190
|
+
filter = @defined[filter] unless filter.is_a? Filter
|
178
191
|
return unless filter
|
179
192
|
|
180
193
|
filter.enabled = false
|
181
|
-
|
194
|
+
rebuild_enabled! filter.type
|
182
195
|
end
|
183
196
|
|
184
197
|
# Turn on disabled +filter+ by name or Filter object.
|
185
198
|
def on(filter)
|
186
|
-
filter = defined[filter] unless filter.is_a? Filter
|
199
|
+
filter = @defined[filter] unless filter.is_a? Filter
|
187
200
|
return unless filter
|
188
201
|
|
189
202
|
filter.enabled = true
|
190
|
-
|
203
|
+
rebuild_enabled! filter.type
|
191
204
|
end
|
192
205
|
end
|
206
|
+
|
207
|
+
Filters.defined = {}
|
208
|
+
Filters.by_type = Hash.new([])
|
209
|
+
Filters.active_enabled = Hash.new([])
|
210
|
+
Filters.passive_enabled = Hash.new([])
|
211
|
+
Filters.enabled = Hash.new([])
|
212
|
+
|
213
|
+
Filter = Struct.new(:name, :type, :block, :enabled, :passive) do
|
214
|
+
def call(*params); block.call(*params); end
|
215
|
+
def enabled?; enabled; end
|
216
|
+
def passive?; passive; end
|
217
|
+
end
|
193
218
|
end
|
194
219
|
|
195
220
|
Filters.add('proc', :procedure) do |content, config, *params|
|
@@ -218,31 +243,31 @@ module R18n
|
|
218
243
|
"#{translated}[#{untranslated}]"
|
219
244
|
end
|
220
245
|
|
221
|
-
Filters.add('escape', :escape_html) do |content, config|
|
246
|
+
Filters.add('escape', :escape_html, :passive => true) do |content, config|
|
222
247
|
config[:dont_escape_html] = true
|
223
248
|
Utils.escape_html(content)
|
224
249
|
end
|
225
250
|
|
226
|
-
Filters.add('html', :dont_escape_html) do |content, config|
|
251
|
+
Filters.add('html', :dont_escape_html, :passive => true) do |content, config|
|
227
252
|
config[:dont_escape_html] = true
|
228
253
|
content
|
229
254
|
end
|
230
255
|
|
231
|
-
Filters.add(String, :global_escape_html) do |
|
256
|
+
Filters.add(String, :global_escape_html, :passive => true) do |html, config|
|
232
257
|
if config[:dont_escape_html]
|
233
|
-
|
258
|
+
html
|
234
259
|
else
|
235
|
-
Utils.escape_html(
|
260
|
+
Utils.escape_html(html)
|
236
261
|
end
|
237
262
|
end
|
238
263
|
Filters.off(:global_escape_html)
|
239
264
|
|
240
|
-
Filters.add('markdown', :maruku) do |content, config|
|
265
|
+
Filters.add('markdown', :maruku, :passive => true) do |content, config|
|
241
266
|
require 'maruku'
|
242
267
|
::Maruku.new(content).to_html
|
243
268
|
end
|
244
269
|
|
245
|
-
Filters.add('textile', :redcloth) do |content, config|
|
270
|
+
Filters.add('textile', :redcloth, :passive => true) do |content, config|
|
246
271
|
require 'redcloth'
|
247
272
|
::RedCloth.new(content).to_html
|
248
273
|
end
|
data/lib/r18n-core/translated.rb
CHANGED
@@ -133,10 +133,12 @@ module R18n
|
|
133
133
|
path = "\#{self.class.name}##{name}"
|
134
134
|
type = self.class.translation_types[#{name.inspect}]
|
135
135
|
if type
|
136
|
-
return R18n::Filters.process(
|
136
|
+
return R18n::Filters.process(R18n::Filters.enabled,
|
137
|
+
type, result, locale, path, params)
|
137
138
|
else
|
138
139
|
result = TranslatedString.new(result, locale, path)
|
139
|
-
return R18n::Filters.process_string(
|
140
|
+
return R18n::Filters.process_string(R18n::Filters.enabled,
|
141
|
+
result, path, params)
|
140
142
|
end
|
141
143
|
end
|
142
144
|
|
@@ -91,12 +91,15 @@ module R18n
|
|
91
91
|
when Hash
|
92
92
|
value = Translation.new(@locale, path, locale, value)
|
93
93
|
when String
|
94
|
-
|
95
|
-
|
96
|
-
value = Typed.new(value.type_id, value.value, locale, path)
|
94
|
+
v = TranslatedString.new(value, locale, path)
|
95
|
+
value = Filters.process_string(Filters.passive_enabled, v, path, {})
|
97
96
|
when Typed
|
98
97
|
value.locale = locale
|
99
98
|
value.path = path
|
99
|
+
unless Filters.passive_enabled[value.type].empty?
|
100
|
+
value = Filters.process(Filters.passive_enabled, value.type,
|
101
|
+
value.value, value.locale, value.path, {})
|
102
|
+
end
|
100
103
|
end
|
101
104
|
@data[name] = value
|
102
105
|
elsif @data[name].is_a? Translation
|
@@ -107,7 +110,8 @@ module R18n
|
|
107
110
|
|
108
111
|
# Use untranslated filter to print path.
|
109
112
|
def to_s
|
110
|
-
Filters.process(Untranslated, @path, @locale, @path,
|
113
|
+
Filters.process(Filters.enabled, Untranslated, @path, @locale, @path,
|
114
|
+
[@path, '', @path])
|
111
115
|
end
|
112
116
|
|
113
117
|
# Return +default+.
|
@@ -133,10 +137,10 @@ module R18n
|
|
133
137
|
value = @data[name.to_s]
|
134
138
|
case value
|
135
139
|
when TranslatedString
|
136
|
-
Filters.process_string(value, @path, params)
|
140
|
+
Filters.process_string(Filters.active_enabled, value, @path, params)
|
137
141
|
when Typed
|
138
|
-
Filters.process(
|
139
|
-
params)
|
142
|
+
Filters.process(Filters.active_enabled, value.type, value.value,
|
143
|
+
value.locale, value.path, params)
|
140
144
|
when nil
|
141
145
|
translated = @path.empty? ? '' : "#{@path}."
|
142
146
|
Untranslated.new(translated, name.to_s, @locale)
|
data/lib/r18n-core/version.rb
CHANGED
@@ -50,7 +50,8 @@ module R18n
|
|
50
50
|
|
51
51
|
# Return Hash with translations for +locale+.
|
52
52
|
def load(locale)
|
53
|
-
|
53
|
+
file = File.join(@dir, "#{locale.code.downcase}.yml")
|
54
|
+
transform(::YAML::load(IO.read(file)))
|
54
55
|
end
|
55
56
|
|
56
57
|
# YAML loader with same +dir+ will be have same +hash+.
|
@@ -62,6 +63,18 @@ module R18n
|
|
62
63
|
def ==(loader)
|
63
64
|
self.class == loader.class and self.dir == loader.dir
|
64
65
|
end
|
66
|
+
|
67
|
+
# Wrap YAML private types to Typed.
|
68
|
+
def transform(hash)
|
69
|
+
Hash[hash.map { |key, value|
|
70
|
+
if value.is_a? ::YAML::PrivateType
|
71
|
+
value = Typed.new(value.type_id, value.value)
|
72
|
+
elsif value.is_a? Hash
|
73
|
+
value = transform(value)
|
74
|
+
end
|
75
|
+
[key, value]
|
76
|
+
}]
|
77
|
+
end
|
65
78
|
end
|
66
79
|
end
|
67
80
|
end
|
data/spec/filters_spec.rb
CHANGED
@@ -6,6 +6,7 @@ describe R18n::Filters do
|
|
6
6
|
@system = R18n::Filters.defined.values
|
7
7
|
@enabled = R18n::Filters.defined.values.reject { |i| !i.enabled? }
|
8
8
|
@i18n = R18n::I18n.new('en', DIR)
|
9
|
+
@i18n.reload!
|
9
10
|
end
|
10
11
|
|
11
12
|
after do
|
@@ -31,10 +32,24 @@ describe R18n::Filters do
|
|
31
32
|
@i18n.my_tree_filter.should == {'name' => 'value'}
|
32
33
|
end
|
33
34
|
|
35
|
+
it "should use passive filters" do
|
36
|
+
filter = mock()
|
37
|
+
filter.should_receive(:process).twice.and_return(1)
|
38
|
+
|
39
|
+
R18n::Filters.add('my', :passive, :passive => true) { filter.process }
|
40
|
+
|
41
|
+
@i18n.my_filter.should.should == 'value'
|
42
|
+
@i18n.reload!
|
43
|
+
|
44
|
+
@i18n.my_tree_filter.should == 1
|
45
|
+
@i18n.my_filter.should == 1
|
46
|
+
@i18n.my_filter.should == 1
|
47
|
+
end
|
48
|
+
|
34
49
|
it "should use cascade filters" do
|
35
|
-
filter = R18n::Filters.add('my', :one)
|
36
|
-
filter = R18n::Filters.add('my', :two)
|
37
|
-
filter = R18n::Filters.add('my', :three, 0) { |i,
|
50
|
+
filter = R18n::Filters.add('my', :one) { |i, config| i + '1' }
|
51
|
+
filter = R18n::Filters.add('my', :two) { |i, config| i + '2' }
|
52
|
+
filter = R18n::Filters.add('my', :three, :position => 0) { |i, c| i + '3' }
|
38
53
|
@i18n.my_filter.should == 'value312'
|
39
54
|
end
|
40
55
|
|
@@ -42,7 +57,7 @@ describe R18n::Filters do
|
|
42
57
|
R18n::Filters.instance_variable_set(:@last_auto_name, 0)
|
43
58
|
|
44
59
|
R18n::Filters.add('some').name.should == 1
|
45
|
-
R18n::Filters.add('some').name.should == 2
|
60
|
+
R18n::Filters.add('some', :position => 0).name.should == 2
|
46
61
|
|
47
62
|
R18n::Filters.add('some', 3)
|
48
63
|
R18n::Filters.add('some').name.should == 4
|
@@ -101,7 +116,7 @@ describe R18n::Filters do
|
|
101
116
|
R18n::Filters.add('my') { |content, config| config[:new_secret] ? 2 : 1 }
|
102
117
|
@i18n.my_filter.should == 1
|
103
118
|
|
104
|
-
R18n::Filters.add('my',
|
119
|
+
R18n::Filters.add('my', :second, :position => 0) do |content, config|
|
105
120
|
config[:new_secret] = true
|
106
121
|
content
|
107
122
|
end
|
@@ -175,13 +190,16 @@ describe R18n::Filters do
|
|
175
190
|
@i18n.greater.should == '1 < 2 is true'
|
176
191
|
|
177
192
|
R18n::Filters.on(:global_escape_html)
|
193
|
+
@i18n.reload!
|
178
194
|
@i18n.greater.should == '1 < 2 is true'
|
179
195
|
@i18n.html.should == '<script>true && false</script>'
|
180
196
|
end
|
181
197
|
|
182
198
|
it "should have filter to disable global HTML escape" do
|
183
199
|
@i18n.no_escape.should == '<b>Warning</b>'
|
200
|
+
|
184
201
|
R18n::Filters.on(:global_escape_html)
|
202
|
+
@i18n.reload!
|
185
203
|
@i18n.no_escape.should == '<b>Warning</b>'
|
186
204
|
end
|
187
205
|
|
data/spec/yaml_loader_spec.rb
CHANGED
@@ -23,7 +23,8 @@ describe R18n::Loader::YAML do
|
|
23
23
|
|
24
24
|
it "should load translation" do
|
25
25
|
@loader.load(R18n::Locale.load('ru')).should == {
|
26
|
-
'one' => 'Один', 'in' => {'another' => {'level' => 'Иерархический'}}
|
26
|
+
'one' => 'Один', 'in' => {'another' => {'level' => 'Иерархический'}},
|
27
|
+
'typed' => R18n::Typed.new('my', 'value') }
|
27
28
|
end
|
28
29
|
|
29
30
|
it "should return hash by dir" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: r18n-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrey "A.I." Sitnik
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-11 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|