opal 0.3.22 → 0.3.25
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -1
- data/Gemfile +1 -9
- data/README.md +46 -5
- data/Rakefile +4 -94
- data/core/array.rb +13 -46
- data/core/basic_object.rb +2 -12
- data/core/boolean.rb +1 -1
- data/core/browser.js +27 -1
- data/core/class.rb +1 -7
- data/core/enumerable.rb +3 -15
- data/core/error.rb +2 -4
- data/core/hash.rb +9 -18
- data/core/json.rb +5 -0
- data/core/kernel.rb +2 -21
- data/core/load_order +5 -7
- data/core/nil_class.rb +4 -0
- data/core/numeric.rb +0 -6
- data/core/object.rb +1 -5
- data/core/proc.rb +0 -4
- data/core/range.rb +10 -17
- data/core/regexp.rb +2 -6
- data/core/runtime.js +2 -26
- data/core/string.rb +28 -26
- data/core/struct.rb +0 -4
- data/core/{erb.rb → templates.rb} +6 -4
- data/core/time.rb +7 -19
- data/core/top_self.rb +2 -2
- data/lib/opal.rb +13 -2
- data/lib/opal/builder.rb +3 -3
- data/lib/opal/erb_parser.rb +3 -2
- data/lib/opal/parser.rb +10 -2
- data/lib/opal/rake_task.rb +10 -2
- data/lib/opal/scope.rb +6 -1
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +1 -3
- data/spec/core/array/constructor_spec.rb +0 -8
- data/spec/core/enumerable/drop_while_spec.rb +0 -4
- data/spec/core/enumerable/find_index_spec.rb +0 -4
- data/spec/core/enumerable/select_spec.rb +13 -0
- data/spec/core/kernel/respond_to_spec.rb +4 -0
- data/spec/core/string/empty_spec.rb +0 -1
- data/spec/core/string/include_spec.rb +0 -6
- data/spec/core/string/swapcase_spec.rb +0 -5
- data/spec/core/string/to_s_spec.rb +0 -7
- data/spec/core/string/to_str_spec.rb +0 -7
- data/spec/lib/erb_parser/simple.erb +1 -0
- data/spec/{grammar → lib/grammar}/alias_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/and_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/array_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/attrasgn_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/begin_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/block_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/break_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/call_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/class_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/const_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/cvar_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/def_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/false_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/file_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/gvar_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/hash_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/iasgn_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/if_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/iter_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/ivar_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/lambda_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/lasgn_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/line_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/lvar_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/masgn_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/module_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/nil_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/not_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/op_asgn1_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/op_asgn2_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/or_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/return_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/sclass_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/self_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/str_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/super_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/true_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/undef_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/unless_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/while_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/xstr_spec.rb +0 -0
- data/spec/{grammar → lib/grammar}/yield_spec.rb +0 -0
- data/spec/{parser → lib/parser}/simple_spec.rb +1 -1
- data/spec/opal/erb/erb_spec.rb +10 -2
- data/spec/opal/string/demodulize_spec.rb +10 -0
- data/spec/opal/string/underscore_spec.rb +17 -0
- data/spec/spec_helper.rb +1 -1
- data/vendor/opal_spec_runner.js +43 -0
- metadata +99 -114
- data/.rspec +0 -2
- data/docs/index.md +0 -616
- data/docs/post.html +0 -3
- data/docs/pre.html +0 -35
- data/docs/try.html +0 -52
- data/spec/core/string/fixtures/classes.rb +0 -3
- data/spec/opal/array/subclassing_spec.rb +0 -32
- data/spec/opal/exception/subclassing_spec.rb +0 -17
- data/spec/opal/string/subclassing_spec.rb +0 -26
data/core/regexp.rb
CHANGED
@@ -11,9 +11,7 @@ class Regexp < `RegExp`
|
|
11
11
|
`other.constructor == RegExp && #{self}.toString() === other.toString()`
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
`#{self}.test(obj)`
|
16
|
-
end
|
14
|
+
alias_native :===, :test
|
17
15
|
|
18
16
|
def =~(string)
|
19
17
|
%x{
|
@@ -36,9 +34,7 @@ class Regexp < `RegExp`
|
|
36
34
|
|
37
35
|
alias eql? ==
|
38
36
|
|
39
|
-
|
40
|
-
`#{self}.toString()`
|
41
|
-
end
|
37
|
+
alias_native :inspect, :toString
|
42
38
|
|
43
39
|
def match(pattern)
|
44
40
|
%x{
|
data/core/runtime.js
CHANGED
@@ -238,30 +238,6 @@ var bridge_class = function(constructor) {
|
|
238
238
|
|
239
239
|
bridged_classes.push(constructor);
|
240
240
|
|
241
|
-
var allocator = function(initializer) {
|
242
|
-
var result, kls = this, methods = kls._methods, proto = kls.prototype;
|
243
|
-
|
244
|
-
if (initializer == null) {
|
245
|
-
result = new constructor
|
246
|
-
}
|
247
|
-
else {
|
248
|
-
result = new constructor(initializer);
|
249
|
-
}
|
250
|
-
|
251
|
-
if (kls === constructor) {
|
252
|
-
return result;
|
253
|
-
}
|
254
|
-
|
255
|
-
result._klass = kls;
|
256
|
-
|
257
|
-
for (var i = 0, length = methods.length; i < length; i++) {
|
258
|
-
var method = methods[i];
|
259
|
-
result[method] = proto[method];
|
260
|
-
}
|
261
|
-
|
262
|
-
return result;
|
263
|
-
};
|
264
|
-
|
265
241
|
var table = Object.prototype, methods = Object._methods;
|
266
242
|
|
267
243
|
for (var i = 0, length = methods.length; i < length; i++) {
|
@@ -269,13 +245,13 @@ var bridge_class = function(constructor) {
|
|
269
245
|
constructor.prototype[m] = table[m];
|
270
246
|
}
|
271
247
|
|
272
|
-
constructor.$allocate = allocator;
|
273
|
-
|
274
248
|
constructor._smethods.push('$allocate');
|
275
249
|
|
276
250
|
return constructor;
|
277
251
|
};
|
278
252
|
|
253
|
+
Opal.puts = function(a) { console.log(a); };
|
254
|
+
|
279
255
|
// Initialization
|
280
256
|
// --------------
|
281
257
|
|
data/core/string.rb
CHANGED
@@ -11,7 +11,7 @@ class String < `String`
|
|
11
11
|
|
12
12
|
def self.new(str = '')
|
13
13
|
%x{
|
14
|
-
return
|
14
|
+
return new String(str)
|
15
15
|
}
|
16
16
|
end
|
17
17
|
|
@@ -91,7 +91,6 @@ class String < `String`
|
|
91
91
|
}
|
92
92
|
end
|
93
93
|
|
94
|
-
# TODO: implement range based accessors
|
95
94
|
def [](index, length)
|
96
95
|
%x{
|
97
96
|
var size = #{self}.length;
|
@@ -151,8 +150,6 @@ class String < `String`
|
|
151
150
|
end
|
152
151
|
|
153
152
|
def chars
|
154
|
-
return enum_for :chars unless block_given?
|
155
|
-
|
156
153
|
%x{
|
157
154
|
for (var i = 0, length = #{self}.length; i < length; i++) {
|
158
155
|
#{yield `#{self}.charAt(i)`}
|
@@ -183,16 +180,24 @@ class String < `String`
|
|
183
180
|
def count(str)
|
184
181
|
`(#{self}.length - #{self}.replace(new RegExp(str,"g"), '').length) / str.length`
|
185
182
|
end
|
183
|
+
|
184
|
+
def demodulize
|
185
|
+
%x{
|
186
|
+
var idx = #{self}.lastIndexOf('::');
|
186
187
|
|
187
|
-
|
188
|
-
|
188
|
+
if (idx > -1) {
|
189
|
+
return #{self}.substr(idx + 2);
|
190
|
+
}
|
191
|
+
|
192
|
+
return #{self};
|
193
|
+
}
|
189
194
|
end
|
190
195
|
|
196
|
+
alias_native :downcase, :toLowerCase
|
197
|
+
|
191
198
|
alias each_char chars
|
192
199
|
|
193
200
|
def each_line (separator = $/)
|
194
|
-
return enum_for :each_line, separator unless block_given?
|
195
|
-
|
196
201
|
%x{
|
197
202
|
var splitted = #{self}.split(separator);
|
198
203
|
|
@@ -226,13 +231,9 @@ class String < `String`
|
|
226
231
|
`#{self}.toString() === val.toString()`
|
227
232
|
end
|
228
233
|
|
229
|
-
|
230
|
-
`#{self}.charCodeAt(idx)`
|
231
|
-
end
|
234
|
+
alias_native :getbyte, :charCodeAt
|
232
235
|
|
233
236
|
def gsub(pattern, replace, &block)
|
234
|
-
return enum_for :gsub, pattern, replace if !block && `pattern == null`
|
235
|
-
|
236
237
|
if pattern.is_a?(String)
|
237
238
|
pattern = /#{Regexp.escape(pattern)}/
|
238
239
|
end
|
@@ -246,9 +247,7 @@ class String < `String`
|
|
246
247
|
}
|
247
248
|
end
|
248
249
|
|
249
|
-
|
250
|
-
`#{self}.toString()`
|
251
|
-
end
|
250
|
+
alias_native :hash, :toString
|
252
251
|
|
253
252
|
def hex
|
254
253
|
to_i 16
|
@@ -259,11 +258,11 @@ class String < `String`
|
|
259
258
|
end
|
260
259
|
|
261
260
|
def index(what, offset)
|
262
|
-
unless String === what || Regexp === what
|
263
|
-
raise TypeError, "type mismatch: #{what.class} given"
|
264
|
-
end
|
265
|
-
|
266
261
|
%x{
|
262
|
+
if (!what._isString && !what._isRegexp) {
|
263
|
+
throw new Error('type mismatch');
|
264
|
+
}
|
265
|
+
|
267
266
|
var result = -1;
|
268
267
|
|
269
268
|
if (offset != null) {
|
@@ -502,17 +501,20 @@ class String < `String`
|
|
502
501
|
}
|
503
502
|
end
|
504
503
|
|
505
|
-
|
506
|
-
`#{self}.toString()`
|
507
|
-
end
|
504
|
+
alias_native :to_s, :toString
|
508
505
|
|
509
506
|
alias to_str to_s
|
510
507
|
|
511
508
|
alias to_sym intern
|
512
|
-
|
513
|
-
def
|
514
|
-
`#{self}.
|
509
|
+
|
510
|
+
def underscore
|
511
|
+
`#{self}.replace(/[-\\s]+/g, '_')
|
512
|
+
.replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1_$2')
|
513
|
+
.replace(/([a-z\\d])([A-Z])/g, '$1_$2')
|
514
|
+
.toLowerCase()`
|
515
515
|
end
|
516
|
+
|
517
|
+
alias_native :upcase, :toUpperCase
|
516
518
|
end
|
517
519
|
|
518
520
|
Symbol = String
|
data/core/struct.rb
CHANGED
@@ -74,14 +74,10 @@ class Struct
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def each
|
77
|
-
return enum_for :each unless block_given?
|
78
|
-
|
79
77
|
members.each { |name| yield self[name] }
|
80
78
|
end
|
81
79
|
|
82
80
|
def each_pair
|
83
|
-
return enum_for :each_pair unless block_given?
|
84
|
-
|
85
81
|
members.each { |name| yield name, self[name] }
|
86
82
|
end
|
87
83
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# A
|
1
|
+
# A wapper for ERB templates in Opal. Other templates may be used
|
2
2
|
class ERB
|
3
3
|
|
4
4
|
# @private Stores all registered instances
|
@@ -20,11 +20,13 @@ class ERB
|
|
20
20
|
# implementation uses a normal object as a context.
|
21
21
|
#
|
22
22
|
# view = UserView.new
|
23
|
-
# ERB[:user_view].
|
23
|
+
# ERB[:user_view].render(view)
|
24
24
|
#
|
25
25
|
# @param [Object] context
|
26
26
|
# @result [String]
|
27
|
-
def
|
28
|
-
|
27
|
+
def render(content)
|
28
|
+
content.instance_eval(&@body)
|
29
29
|
end
|
30
|
+
|
31
|
+
alias :result :render
|
30
32
|
end
|
data/core/time.rb
CHANGED
@@ -2,7 +2,7 @@ class Time < `Date`
|
|
2
2
|
include Comparable
|
3
3
|
|
4
4
|
def self.at(seconds, frac = 0)
|
5
|
-
|
5
|
+
`new Date(seconds * 1000 + frac)`
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.new(year, month, day, hour, minute, second, millisecond)
|
@@ -44,9 +44,7 @@ class Time < `Date`
|
|
44
44
|
to_f <=> other.to_f
|
45
45
|
end
|
46
46
|
|
47
|
-
|
48
|
-
`#{self}.getDate()`
|
49
|
-
end
|
47
|
+
alias_native :day, :getDate
|
50
48
|
|
51
49
|
def eql?(other)
|
52
50
|
other.is_a?(Time) && (self <=> other).zero?
|
@@ -56,15 +54,11 @@ class Time < `Date`
|
|
56
54
|
`#{self}.getDay() === 5`
|
57
55
|
end
|
58
56
|
|
59
|
-
|
60
|
-
`#{self}.getHours()`
|
61
|
-
end
|
57
|
+
alias_native :hour, :getHours
|
62
58
|
|
63
59
|
alias mday day
|
64
60
|
|
65
|
-
|
66
|
-
`#{self}.getMinutes()`
|
67
|
-
end
|
61
|
+
alias_native :min, :getMinutes
|
68
62
|
|
69
63
|
def mon
|
70
64
|
`#{self}.getMonth() + 1`
|
@@ -80,9 +74,7 @@ class Time < `Date`
|
|
80
74
|
`#{self}.getDay() === 6`
|
81
75
|
end
|
82
76
|
|
83
|
-
|
84
|
-
`#{self}.getSeconds()`
|
85
|
-
end
|
77
|
+
alias_native :sec, :getSeconds
|
86
78
|
|
87
79
|
def sunday?
|
88
80
|
`#{self}.getDay() === 0`
|
@@ -104,15 +96,11 @@ class Time < `Date`
|
|
104
96
|
`#{self}.getDay() === 2`
|
105
97
|
end
|
106
98
|
|
107
|
-
|
108
|
-
`#{self}.getDay()`
|
109
|
-
end
|
99
|
+
alias_native :wday, :getDay
|
110
100
|
|
111
101
|
def wednesday?
|
112
102
|
`#{self}.getDay() === 3`
|
113
103
|
end
|
114
104
|
|
115
|
-
|
116
|
-
`#{self}.getFullYear()`
|
117
|
-
end
|
105
|
+
alias_native :year, :getFullYear
|
118
106
|
end
|
data/core/top_self.rb
CHANGED
data/lib/opal.rb
CHANGED
@@ -58,6 +58,17 @@ module Opal
|
|
58
58
|
].join("\n")
|
59
59
|
end
|
60
60
|
|
61
|
+
# Returns parser prebuilt for js-environments.
|
62
|
+
#
|
63
|
+
# @return [String]
|
64
|
+
def self.parser_code
|
65
|
+
[
|
66
|
+
Builder.new(:files => %w(racc.rb strscan.rb), :dir => self.core_dir).build,
|
67
|
+
self.build_gem('opal'),
|
68
|
+
File.read(File.join self.core_dir, 'browser.js')
|
69
|
+
].join("\n")
|
70
|
+
end
|
71
|
+
|
61
72
|
# Build gem with given name to a string.
|
62
73
|
#
|
63
74
|
# Opal.build_gem 'opal-spec'
|
@@ -81,8 +92,8 @@ module Opal
|
|
81
92
|
#
|
82
93
|
# @param [String] files files to build
|
83
94
|
# @return [String]
|
84
|
-
def self.build_files(files)
|
85
|
-
Builder.new(:files => files).build
|
95
|
+
def self.build_files(files, dir=nil)
|
96
|
+
Builder.new(:files => files, :dir => dir).build
|
86
97
|
end
|
87
98
|
|
88
99
|
def self.opal_dir
|
data/lib/opal/builder.rb
CHANGED
@@ -28,7 +28,7 @@ module Opal
|
|
28
28
|
files = []
|
29
29
|
|
30
30
|
sources.each do |s|
|
31
|
-
s = File.join @dir, s
|
31
|
+
s = File.expand_path(File.join @dir, s)
|
32
32
|
if File.directory? s
|
33
33
|
files.push *Dir[File.join(s, '**/*.{rb,js,erb}')]
|
34
34
|
elsif %w(.rb .js .erb).include? File.extname(s)
|
@@ -71,7 +71,7 @@ module Opal
|
|
71
71
|
code = @parser.parse File.read(file), lib_name
|
72
72
|
@requires[lib_name] = @parser.requires
|
73
73
|
elsif File.extname(file) == '.erb'
|
74
|
-
template_name =
|
74
|
+
template_name = lib_name_for(file).chomp(File.extname(file))
|
75
75
|
code = Opal::ERBParser.new.parse File.read(file), template_name
|
76
76
|
@requires[lib_name] = []
|
77
77
|
else # javascript
|
@@ -89,7 +89,7 @@ module Opal
|
|
89
89
|
def lib_name_for(file)
|
90
90
|
file = file.sub(/^#{@dir}\//, '')
|
91
91
|
file = file.chomp File.extname(file)
|
92
|
-
file.sub(/^(lib|spec)\//, '')
|
92
|
+
file.sub(/^(lib|spec|app)\//, '')
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
data/lib/opal/erb_parser.rb
CHANGED
@@ -9,8 +9,9 @@ module Opal
|
|
9
9
|
|
10
10
|
def compile(str, name)
|
11
11
|
res = "ERB.new('#{name}') do\nout = []\nout.<<(\"" +
|
12
|
-
str.gsub(
|
13
|
-
|
12
|
+
str.gsub('"', '\\"'
|
13
|
+
).gsub(/<%=([\s\S]+?)%>/) do
|
14
|
+
"\")\nout.<<(" + $1.gsub(/\\'/, "'").gsub(/\\"/, '"') + ")\nout.<<(\""
|
14
15
|
end.gsub(/<%([\s\S]+?)%>/) do
|
15
16
|
"\")\n" + $1 + "\nout.<<(\""
|
16
17
|
end + "\")\nout.join\nend"
|
data/lib/opal/parser.rb
CHANGED
@@ -36,8 +36,7 @@ module Opal
|
|
36
36
|
|
37
37
|
@helpers = {
|
38
38
|
:breaker => true,
|
39
|
-
:slice => true
|
40
|
-
:mm => true
|
39
|
+
:slice => true
|
41
40
|
}
|
42
41
|
|
43
42
|
top @grammar.parse(source, file)
|
@@ -540,6 +539,13 @@ module Opal
|
|
540
539
|
"%s%s = %s.%s" % [@scope.proto, meth, @scope.proto, func]
|
541
540
|
end
|
542
541
|
|
542
|
+
def handle_respond_to(sexp, level)
|
543
|
+
recv, mid, arglist = sexp
|
544
|
+
recv ||= s(:self)
|
545
|
+
meth = process(arglist[1], level) if arglist[1]
|
546
|
+
"(!!#{process(recv, level)}['$' + #{meth}])"
|
547
|
+
end
|
548
|
+
|
543
549
|
# s(:call, recv, :mid, s(:arglist))
|
544
550
|
# s(:call, nil, :mid, s(:arglist))
|
545
551
|
def process_call(sexp, level)
|
@@ -565,6 +571,8 @@ module Opal
|
|
565
571
|
end
|
566
572
|
|
567
573
|
return "//= require #{path[1]}"
|
574
|
+
when :respond_to?
|
575
|
+
return handle_respond_to(sexp, level)
|
568
576
|
end
|
569
577
|
|
570
578
|
splat = arglist[1..-1].any? { |a| a.first == :splat }
|
data/lib/opal/rake_task.rb
CHANGED
@@ -6,12 +6,13 @@ module Opal
|
|
6
6
|
class RakeTask
|
7
7
|
include Rake::DSL if defined? Rake::DSL
|
8
8
|
|
9
|
-
attr_accessor :name, :build_dir, :specs_dir, :files, :dependencies
|
9
|
+
attr_accessor :name, :build_dir, :specs_dir, :files, :dependencies, :parser, :dir
|
10
10
|
|
11
11
|
def initialize(namespace = nil)
|
12
12
|
@project_dir = Dir.getwd
|
13
13
|
|
14
14
|
@name = File.basename(@project_dir)
|
15
|
+
@dir = @project_dir
|
15
16
|
@build_dir = 'build'
|
16
17
|
@specs_dir = 'spec'
|
17
18
|
@files = Dir['lib/**/*.{rb,js,erb}']
|
@@ -40,7 +41,7 @@ module Opal
|
|
40
41
|
task 'opal:build' do
|
41
42
|
out = File.join @build_dir, "#{ @name }.js"
|
42
43
|
puts " * #{out}"
|
43
|
-
write_code Opal.build_files(@files), out
|
44
|
+
write_code Opal.build_files(@files, @dir), out
|
44
45
|
end
|
45
46
|
|
46
47
|
desc "Build specs"
|
@@ -56,6 +57,13 @@ module Opal
|
|
56
57
|
puts " * #{out}"
|
57
58
|
write_code Opal.runtime, out
|
58
59
|
|
60
|
+
# build opal-parser?
|
61
|
+
if @parser
|
62
|
+
out = File.join @build_dir, 'opal-parser.js'
|
63
|
+
puts " * #{out}"
|
64
|
+
write_code Opal.parser_code, out
|
65
|
+
end
|
66
|
+
|
59
67
|
@dependencies.each { |dep| build_gem dep }
|
60
68
|
end
|
61
69
|
|