opal 0.3.6 → 0.3.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +69 -97
- data/bin/opal +2 -2
- data/{lib/core → corelib}/array.rb +85 -56
- data/corelib/boolean.rb +20 -0
- data/corelib/class.rb +58 -0
- data/{lib → corelib}/core.rb +2 -50
- data/corelib/dir.rb +22 -0
- data/{lib/core → corelib}/enumerable.rb +0 -0
- data/corelib/error.rb +19 -0
- data/{lib/core → corelib}/file.rb +7 -9
- data/{lib/core → corelib}/hash.rb +104 -144
- data/{lib/core → corelib}/kernel.rb +38 -44
- data/corelib/load_order +21 -0
- data/{lib/core → corelib}/match_data.rb +0 -0
- data/{lib/core → corelib}/module.rb +12 -8
- data/{lib/core → corelib}/nil_class.rb +2 -2
- data/{lib/core → corelib}/numeric.rb +37 -100
- data/corelib/object.rb +37 -0
- data/{lib/core → corelib}/proc.rb +3 -3
- data/corelib/range.rb +27 -0
- data/{lib/core → corelib}/regexp.rb +1 -1
- data/{lib/core → corelib}/string.rb +16 -107
- data/{lib/core → corelib}/top_self.rb +0 -0
- data/lib/opal.rb +7 -0
- data/lib/opal/browserify.rb +34 -0
- data/{opal_lib → lib}/opal/builder.rb +70 -24
- data/lib/opal/command.rb +52 -0
- data/lib/opal/context.rb +197 -0
- data/{opal_lib/opal/ruby/parser.rb → lib/opal/lexer.rb} +20 -4
- data/{opal_lib/opal/ruby → lib/opal}/nodes.rb +238 -127
- data/lib/opal/parser.rb +4894 -0
- data/{opal_lib/opal/ruby/ruby_parser.y → lib/opal/parser.y} +38 -18
- data/lib/rbp.rb +2 -0
- data/lib/rbp/package.rb +49 -0
- data/runtime/class.js +216 -189
- data/runtime/fs.js +2 -2
- data/runtime/init.js +242 -244
- data/runtime/loader.js +78 -99
- data/runtime/module.js +34 -40
- data/runtime/post.js +2 -2
- data/runtime/pre.js +1 -1
- data/runtime/runtime.js +129 -135
- data/{lib → stdlib}/dev.rb +10 -10
- data/{lib → stdlib}/racc/parser.rb +0 -6
- data/{lib → stdlib}/strscan.rb +4 -4
- metadata +57 -105
- data/lib/core/basic_object.rb +0 -51
- data/lib/core/class.rb +0 -38
- data/lib/core/dir.rb +0 -26
- data/lib/core/error.rb +0 -75
- data/lib/core/false_class.rb +0 -81
- data/lib/core/object.rb +0 -6
- data/lib/core/range.rb +0 -27
- data/lib/core/symbol.rb +0 -42
- data/lib/core/true_class.rb +0 -41
- data/lib/ospec.rb +0 -7
- data/lib/ospec/autorun.rb +0 -8
- data/lib/ospec/dsl.rb +0 -15
- data/lib/ospec/example.rb +0 -11
- data/lib/ospec/example/before_and_after_hooks.rb +0 -56
- data/lib/ospec/example/errors.rb +0 -17
- data/lib/ospec/example/example_group.rb +0 -12
- data/lib/ospec/example/example_group_factory.rb +0 -18
- data/lib/ospec/example/example_group_hierarchy.rb +0 -21
- data/lib/ospec/example/example_group_methods.rb +0 -100
- data/lib/ospec/example/example_group_proxy.rb +0 -15
- data/lib/ospec/example/example_methods.rb +0 -46
- data/lib/ospec/example/example_proxy.rb +0 -18
- data/lib/ospec/expectations.rb +0 -19
- data/lib/ospec/expectations/errors.rb +0 -8
- data/lib/ospec/expectations/fail_with.rb +0 -9
- data/lib/ospec/expectations/handler.rb +0 -33
- data/lib/ospec/helpers/scratch.rb +0 -18
- data/lib/ospec/matchers.rb +0 -24
- data/lib/ospec/matchers/be.rb +0 -1
- data/lib/ospec/matchers/generated_descriptions.rb +0 -20
- data/lib/ospec/matchers/operator_matcher.rb +0 -54
- data/lib/ospec/matchers/raise_error.rb +0 -38
- data/lib/ospec/runner.rb +0 -90
- data/lib/ospec/runner/example_group_runner.rb +0 -41
- data/lib/ospec/runner/formatter/html_formatter.rb +0 -139
- data/lib/ospec/runner/formatter/terminal_formatter.rb +0 -48
- data/lib/ospec/runner/options.rb +0 -34
- data/lib/ospec/runner/reporter.rb +0 -82
- data/opal_lib/opal.rb +0 -16
- data/opal_lib/opal/build_methods.rb +0 -51
- data/opal_lib/opal/bundle.rb +0 -70
- data/opal_lib/opal/command.rb +0 -68
- data/opal_lib/opal/context.rb +0 -81
- data/opal_lib/opal/context/console.rb +0 -10
- data/opal_lib/opal/context/file_system.rb +0 -34
- data/opal_lib/opal/context/loader.rb +0 -135
- data/opal_lib/opal/gem.rb +0 -84
- data/opal_lib/opal/rake/builder_task.rb +0 -44
- data/opal_lib/opal/rake/spec_task.rb +0 -32
- data/opal_lib/opal/ruby/ruby_parser.rb +0 -4862
- data/opal_lib/opal/version.rb +0 -4
- data/runtime/debug.js +0 -84
data/corelib/object.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Core object in hierarchy. Most of the implementation of this core
|
2
|
+
# object are implemented in {Kernel}.
|
3
|
+
class Object
|
4
|
+
|
5
|
+
def initialize(*a)
|
6
|
+
# ...
|
7
|
+
end
|
8
|
+
|
9
|
+
def ==(other)
|
10
|
+
`return self === other;`
|
11
|
+
end
|
12
|
+
|
13
|
+
def equal?(other)
|
14
|
+
self == other
|
15
|
+
end
|
16
|
+
|
17
|
+
def __send__(method_id, *args, &block)
|
18
|
+
`var method = self['m$' + method_id];
|
19
|
+
|
20
|
+
if ($B.f == arguments.callee) {
|
21
|
+
$B.f = method;
|
22
|
+
}
|
23
|
+
|
24
|
+
return method.apply(self, args);`
|
25
|
+
end
|
26
|
+
|
27
|
+
def instance_eval(&block)
|
28
|
+
raise ArgumentError, "block not supplied" unless block_given?
|
29
|
+
`block.call(self);`
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(sym, *args)
|
34
|
+
raise NoMethodError, "undefined method `#{sym}` for #{self.inspect}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -41,15 +41,15 @@ class Proc
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def call(*args)
|
44
|
-
`
|
44
|
+
`return self.apply(self.o$s,args);`
|
45
45
|
end
|
46
46
|
|
47
47
|
def to_s
|
48
|
-
`return "#<Proc:0x" + (self.$
|
48
|
+
`return "#<Proc:0x" + (self.$h() * 400487).toString(16) + (self.$lambda ? ' (lambda)' : '') + ">";`
|
49
49
|
end
|
50
50
|
|
51
51
|
def lambda?
|
52
|
-
`return self.$
|
52
|
+
`return self.$lambda;`
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
data/corelib/range.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
class Range
|
2
|
+
|
3
|
+
def begin
|
4
|
+
`return self.beg;`
|
5
|
+
end
|
6
|
+
|
7
|
+
alias_method :first, :begin
|
8
|
+
|
9
|
+
def end
|
10
|
+
`return self.end;`
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
`var str = #{`self.beg`.to_s};
|
15
|
+
var str2 = #{`self.end`.to_s};
|
16
|
+
var join = self.exc ? '...' : '..';
|
17
|
+
return str + join + str2;`
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
`var str = #{`self.beg`.inspect};
|
22
|
+
var str2 = #{`self.end`.inspect};
|
23
|
+
var join = self.exc ? '...' : '..';
|
24
|
+
return str + join + str2;`
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -1,99 +1,13 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
-
# String objects holds a sequence of bytes, typically representing
|
4
|
-
# characters. Strings may be constructed by using methods like
|
5
|
-
# {String.new} or literals, like the following:
|
6
|
-
#
|
7
|
-
# String.new("foo") # => "foo"
|
8
|
-
# "bar" # => "bar"
|
9
|
-
#
|
10
|
-
# Strings in Opal are immutable; which means that their contents cannot
|
11
|
-
# be changed. This means that a lot of methods like `strip!` are not
|
12
|
-
# present, and will yield a `NoMethodError`. Thier immutable
|
13
|
-
# counterparts are still available, which typically just return a new
|
14
|
-
# string.
|
15
|
-
#
|
16
|
-
# Implementation details
|
17
|
-
# ----------------------
|
18
|
-
#
|
19
|
-
# Ruby strings are toll-free bridged to native javascript strings,
|
20
|
-
# meaning that anywhere that a ruby string is required, a normal
|
21
|
-
# javascript string may be passed. This dramatically improves the
|
22
|
-
# performance of Opal due to a lower overhead in allocating strings as
|
23
|
-
# well as the ability to used functions of the String prototype to
|
24
|
-
# perform many of the core ruby methods.
|
25
|
-
#
|
26
|
-
# It is due to this limitation that strings are immutable. Javascript
|
27
|
-
# strings are immutable too, which limits what can be done with them in
|
28
|
-
# regards to Ruby methods.
|
29
|
-
#
|
30
|
-
# Ruby compatibility
|
31
|
-
# ------------------
|
32
|
-
#
|
33
|
-
# As discussed, {String} instances are immutable so they do not
|
34
|
-
# implement any of the self mutable methods found in the ruby core
|
35
|
-
# library. Most of these methods have their relative immutable
|
36
|
-
# implementations, or alternative methods to take their place.
|
37
|
-
#
|
38
|
-
# Custom subclasses of {String} can be used, and are constructed in the
|
39
|
-
# {.new} method. To due opals internals, a regular string is constructed
|
40
|
-
# using `new String(string_content)`, and its class and method table
|
41
|
-
# simply pointed at the custom subclass. As these custom subclasses are
|
42
|
-
# simply javascript strings as well, they are also limited to being
|
43
|
-
# immutable. This is because they share the same internal structre as
|
44
|
-
# regular {String} instances.
|
45
|
-
#
|
46
|
-
# String instances will never actually have their {.allocate} methods
|
47
|
-
# called. Due to the way opal bridges strings to javascript, when a new
|
48
|
-
# string is constructed, its value must be know. This is not possible in
|
49
|
-
# `allocate` as the value is not passed. Therefore the creation of
|
50
|
-
# strings (including subclasses) is done in {.new} where the string
|
51
|
-
# value is passed as an argument.
|
52
|
-
#
|
53
|
-
# Finally, strings do not currently include the `Comparable` module, as
|
54
|
-
# it is not yet implemented. The main methods used by {String} from this
|
55
|
-
# module are implemented directly as String methods. When `Comparable`
|
56
|
-
# is implemented, these methods will be moved back to the module.
|
57
3
|
class String
|
58
4
|
|
59
5
|
def self.new(str = "")
|
60
|
-
|
61
|
-
result.$klass = self;
|
62
|
-
result.$m = self.$m_tbl;
|
63
|
-
return result;`
|
6
|
+
str
|
64
7
|
end
|
65
8
|
|
66
|
-
|
67
|
-
|
68
|
-
# @example
|
69
|
-
#
|
70
|
-
# 'Ho! ' * 3
|
71
|
-
# # => 'Ho! Ho! Ho! '
|
72
|
-
#
|
73
|
-
# @param [Numeric] count number of copies
|
74
|
-
# @return [String]
|
75
|
-
def *(count)
|
76
|
-
`var result = [];
|
77
|
-
|
78
|
-
for (var i = 0; i < count; i++) {
|
79
|
-
result.push(self);
|
80
|
-
}
|
81
|
-
|
82
|
-
return result.join('');`
|
83
|
-
end
|
84
|
-
|
85
|
-
# Concatenation - Returns a new string containing `other` concatenated onto
|
86
|
-
# `self`.
|
87
|
-
#
|
88
|
-
# @example
|
89
|
-
#
|
90
|
-
# 'Hello from ' + self.to_s
|
91
|
-
# # => 'Hello from main'
|
92
|
-
#
|
93
|
-
# @param [String] other string to concatenate
|
94
|
-
# @return [String]
|
95
|
-
def +(other)
|
96
|
-
`return self + other;`
|
9
|
+
def ==(other)
|
10
|
+
`return self.valueOf() === other.valueOf();`
|
97
11
|
end
|
98
12
|
|
99
13
|
# Returns a copy of `self` with the first character converted to uppercase and
|
@@ -226,7 +140,7 @@ class String
|
|
226
140
|
`var r = pattern.toString();
|
227
141
|
r = r.substr(1, r.lastIndexOf('/') - 1);
|
228
142
|
r = new RegExp(r, 'g');
|
229
|
-
return self.replace(
|
143
|
+
return self.replace(r, function(str) {
|
230
144
|
return replace;
|
231
145
|
});`
|
232
146
|
end
|
@@ -252,21 +166,12 @@ class String
|
|
252
166
|
# @param [String] other string to compare
|
253
167
|
# @return [-1, 0, 1, nil] result
|
254
168
|
def <=>(other)
|
255
|
-
`if (
|
169
|
+
`if (!(other.o$f & T_STRING)) return nil;
|
256
170
|
else if (self > other) return 1;
|
257
171
|
else if (self < other) return -1;
|
258
172
|
return 0;`
|
259
173
|
end
|
260
174
|
|
261
|
-
# Equality - if other is not a string, returns false. Otherwise, returns true
|
262
|
-
# if self <=> other returns zero.
|
263
|
-
#
|
264
|
-
# @param [String] other string to compare
|
265
|
-
# @return [true, false]
|
266
|
-
def ==(other)
|
267
|
-
`return self.valueOf() === other.valueOf() ? Qtrue : Qfalse;`
|
268
|
-
end
|
269
|
-
|
270
175
|
# Match - if obj is a Regexp, then uses it to match against self, returning
|
271
176
|
# nil if there is no match, or the index of the match location otherwise. If
|
272
177
|
# obj is not a regexp, then it calls =~ on it, using the receiver as an
|
@@ -277,8 +182,8 @@ class String
|
|
277
182
|
# @param [Regexp, Objec] obj
|
278
183
|
# @return [Numeric, nil]
|
279
184
|
def =~(obj)
|
280
|
-
`if (obj
|
281
|
-
|
185
|
+
`if (obj.o$f & T_STRING) {
|
186
|
+
raise(eTypeError, "type mismatch: String given");
|
282
187
|
}`
|
283
188
|
|
284
189
|
obj =~ self
|
@@ -313,7 +218,7 @@ class String
|
|
313
218
|
#
|
314
219
|
# @return [true, false]
|
315
220
|
def empty?
|
316
|
-
`return self.length == 0
|
221
|
+
`return self.length == 0;`
|
317
222
|
end
|
318
223
|
|
319
224
|
# Returns true is self ends with the given suffix.
|
@@ -327,10 +232,10 @@ class String
|
|
327
232
|
# @return [true, false]
|
328
233
|
def end_with?(suffix)
|
329
234
|
`if (self.lastIndexOf(suffix) == self.length - suffix.length) {
|
330
|
-
return
|
235
|
+
return true;
|
331
236
|
}
|
332
237
|
|
333
|
-
return
|
238
|
+
return false;`
|
334
239
|
end
|
335
240
|
|
336
241
|
# Two strings are equal if they have the same length and content.
|
@@ -338,7 +243,11 @@ class String
|
|
338
243
|
# @param [String] other string to compare
|
339
244
|
# @return [true, false]
|
340
245
|
def eql?(other)
|
341
|
-
`return self == other
|
246
|
+
`return self == other;`
|
247
|
+
end
|
248
|
+
|
249
|
+
def +(other)
|
250
|
+
`return self + other;`
|
342
251
|
end
|
343
252
|
|
344
253
|
# Returns true if self contains the given string `other`.
|
@@ -351,7 +260,7 @@ class String
|
|
351
260
|
# @param [String] other string to check for
|
352
261
|
# @return [true, false]
|
353
262
|
def include?(other)
|
354
|
-
`return self.indexOf(other) == -1 ?
|
263
|
+
`return self.indexOf(other) == -1 ? false : true;`
|
355
264
|
end
|
356
265
|
|
357
266
|
# Returns the index of the first occurance of the given `substr` or pattern in
|
File without changes
|
data/lib/opal.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Opal
|
2
|
+
|
3
|
+
# Takes a package and builds it ready for the browser
|
4
|
+
class Browserify
|
5
|
+
|
6
|
+
def initialize(package)
|
7
|
+
@package = package
|
8
|
+
@builder = Builder.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# Simple build - returns a string which can be written to a file
|
12
|
+
# FIXME: hardcoded lib directory to './lib'
|
13
|
+
def build
|
14
|
+
libs = @package.lib_files
|
15
|
+
libs.map! do |f|
|
16
|
+
path = File.join @package.root, './lib', f
|
17
|
+
src = @builder.compile_source path
|
18
|
+
"\"#{f}\": #{src}"
|
19
|
+
end
|
20
|
+
|
21
|
+
bundle = []
|
22
|
+
bundle << %[opal.package({\n]
|
23
|
+
bundle << %[ name: "#{@package.name}",\n]
|
24
|
+
bundle << %[ version: "#{@package.version}",\n]
|
25
|
+
bundle << %[ libs: {\n]
|
26
|
+
bundle << %[ #{libs.join ",\n "}\n]
|
27
|
+
bundle << %[ }\n]
|
28
|
+
bundle << %[});\n]
|
29
|
+
|
30
|
+
bundle.join ''
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -1,52 +1,97 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'opal/build_methods'
|
3
2
|
|
4
3
|
module Opal
|
5
|
-
|
6
|
-
#
|
7
|
-
# building
|
8
|
-
#
|
4
|
+
|
5
|
+
# The Builder class is used for building single ruby sources, or
|
6
|
+
# building the core library ready for the browser/v8 context. It
|
7
|
+
# is not used directly for building packages.
|
9
8
|
class Builder
|
10
|
-
include BuildMethods
|
11
9
|
|
12
10
|
OPAL_PATH = File.expand_path(File.join('..', '..', '..'), __FILE__)
|
13
11
|
|
14
|
-
STDLIB_PATH = File.join OPAL_PATH, '
|
12
|
+
STDLIB_PATH = File.join OPAL_PATH, 'stdlib'
|
15
13
|
|
16
14
|
RUNTIME_PATH = File.join OPAL_PATH, 'runtime'
|
17
15
|
|
18
|
-
|
19
|
-
code = ''
|
16
|
+
CORE_PATH = File.join OPAL_PATH, 'corelib'
|
20
17
|
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
# Returns the result of the compiled file ready for opal to load.
|
19
|
+
#
|
20
|
+
# `relative_path` is used for the name the built file should have.
|
21
|
+
# This is used for building a singular rb or js file into the
|
22
|
+
# compiled output, and will avoid the user's dir setup being exposed
|
23
|
+
# in production code. It will be of the form
|
24
|
+
# `lib/some_lib/some_lib.rb`
|
25
|
+
#
|
26
|
+
# @param [String] full_path The full pathname to the file to build
|
27
|
+
# @paeam [String] relative_path The pathname to be used in the build
|
28
|
+
# file.
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
def wrap_source(full_path, relative_path = nil)
|
32
|
+
relative_path ||= full_path
|
33
|
+
ext = File.extname full_path
|
34
|
+
# relative_path = relative_path.sub(/\.rb/, '.js') if ext == '.rb'
|
35
|
+
content = compile_source full_path
|
36
|
+
|
37
|
+
"opal.lib('#{relative_path}.rb', #{content});\n"
|
38
|
+
end
|
24
39
|
|
25
|
-
|
40
|
+
# Simply compile the given source code at the given path. This is
|
41
|
+
# for compiling ruby or javascript sources only. This can be used
|
42
|
+
# for any method that builds for the browser.
|
43
|
+
#
|
44
|
+
# @param [String] full_path location of the source to build
|
45
|
+
# @return [String] compiled source
|
46
|
+
def compile_source(full_path)
|
47
|
+
ext = File.extname full_path
|
48
|
+
src = File.read full_path
|
49
|
+
|
50
|
+
case ext
|
51
|
+
when '.js'
|
52
|
+
"function($rb, self, __FILE__) { #{src} }"
|
53
|
+
|
54
|
+
when '.rb'
|
55
|
+
src = Opal::Parser.new(src).parse!.generate_top
|
56
|
+
"function($rb, self, __FILE__) { #{src} }"
|
57
|
+
|
58
|
+
else
|
59
|
+
raise "Bad file type for wrapping. Must be ruby or javascript"
|
60
|
+
end
|
26
61
|
end
|
27
62
|
|
28
63
|
# Builds core opal runtime + core libs, and returns as a string.
|
29
64
|
# This can then just be used directly by any compiled code. The
|
30
65
|
# core lib is then auto loaded so it is ready for running.
|
31
66
|
def build_core
|
32
|
-
code =
|
33
|
-
code += build_stdlib('core.rb', 'core/*.rb')
|
34
|
-
code += "opal.require('core');"
|
67
|
+
code = ''
|
35
68
|
|
36
|
-
|
69
|
+
%w[pre runtime init class module fs loader].each do |f|
|
70
|
+
code += File.read(File.join RUNTIME_PATH, f + '.js')
|
71
|
+
end
|
72
|
+
|
73
|
+
order = File.read(File.join(CORE_PATH, 'load_order')).strip.split
|
74
|
+
|
75
|
+
core = order.map do |o|
|
76
|
+
File.read File.join(CORE_PATH, o + '.rb')
|
77
|
+
end
|
78
|
+
|
79
|
+
code += 'var core_lib = function($rb, self, __FILE__) { ' + Opal::Parser.new(core.join).parse!.generate_top + '};'
|
80
|
+
|
81
|
+
code + File.read(File.join RUNTIME_PATH, 'post.js')
|
37
82
|
end
|
38
83
|
|
39
84
|
# Builds the opal parser and dev.rb file, and returns as a string.
|
40
85
|
def build_parser
|
41
86
|
code = ''
|
42
87
|
|
43
|
-
%w[opal/
|
44
|
-
full = File.join OPAL_PATH, '
|
88
|
+
%w[opal/nodes opal/lexer opal/parser].each do |src|
|
89
|
+
full = File.join OPAL_PATH, 'lib', src + '.rb'
|
45
90
|
compiled = compile_source full
|
46
|
-
code += "opal.
|
91
|
+
code += "opal.lib('#{src}.rb', #{compiled});"
|
47
92
|
end
|
48
93
|
|
49
|
-
code += build_stdlib 'racc/parser
|
94
|
+
code += build_stdlib 'racc/parser', 'strscan', 'dev'
|
50
95
|
code += "opal.require('dev');"
|
51
96
|
|
52
97
|
code
|
@@ -57,9 +102,10 @@ module Opal
|
|
57
102
|
def build_stdlib(*files)
|
58
103
|
code = []
|
59
104
|
Dir.chdir(STDLIB_PATH) do
|
60
|
-
|
61
|
-
|
62
|
-
|
105
|
+
files.each do |file|
|
106
|
+
lib = Dir[file + '.rb']
|
107
|
+
full_path = File.join STDLIB_PATH, lib.first
|
108
|
+
code << wrap_source(full_path, file)
|
63
109
|
end
|
64
110
|
end
|
65
111
|
|