nibjs 1.0.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/CHANGELOG.md +5 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +45 -0
- data/LICENCE.js +7 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +16 -0
- data/README.md +64 -0
- data/Rakefile +53 -0
- data/bin/nibjs +4 -0
- data/lib/nibjs/loader.rb +2 -0
- data/lib/nibjs/main.rb +288 -0
- data/lib/nibjs/version.rb +14 -0
- data/lib/nibjs.rb +9 -0
- data/nibjs.gemspec +194 -0
- data/nibjs.noespec +41 -0
- data/src/nibjs.coffee +124 -0
- data/tasks/debug_mail.rake +78 -0
- data/tasks/debug_mail.txt +13 -0
- data/tasks/dist.rake +14 -0
- data/tasks/gem.rake +68 -0
- data/tasks/test.rake +72 -0
- data/tasks/yard.rake +51 -0
- data/test/command/header.js +1 -0
- data/test/command/nibjs_spec.rb +52 -0
- data/test/command/run.rb +3 -0
- data/test/command/sc_coffee_1.exp +31 -0
- data/test/command/sc_coffee_2.exp +26 -0
- data/test/command/sc_coffee_3.exp +25 -0
- data/test/command/sc_coffee_4.exp +26 -0
- data/test/command/sc_coffee_5.exp +24 -0
- data/test/command/sc_common_0.exp +31 -0
- data/test/command/sc_common_1.exp +31 -0
- data/test/command/sc_common_2.exp +32 -0
- data/test/command/sc_common_3.exp +32 -0
- data/test/command/sc_common_4.exp +1 -0
- data/test/command/sc_common_5.exp +1 -0
- data/test/command/scenarios.rb +73 -0
- data/test/fixture.coffee/app.coffee +6 -0
- data/test/fixture.coffee/dependent.coffee +8 -0
- data/test/fixture.coffee/index.coffee +3 -0
- data/test/fixture.js/app.js +9 -0
- data/test/fixture.js/dependent.js +10 -0
- data/test/fixture.js/index.js +3 -0
- data/test/fixture.min.js +28 -0
- data/test/integration/index.html +42 -0
- data/test/integration/integration_test.coffee +29 -0
- data/test/integration/integration_test.js +34 -0
- data/test/integration/integration_test.rb +37 -0
- data/test/integration/jquery-1.4.4.min.js +167 -0
- data/test/jasmine/nibjs_spec.coffee +31 -0
- data/test/jasmine/run.coffee +14 -0
- data/test/nibjs.js +74 -0
- metadata +325 -0
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
nibjs (1.0.0)
|
5
|
+
bundler (~> 1.0)
|
6
|
+
quickl (~> 0.2.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
bluecloth (2.0.10)
|
12
|
+
diff-lcs (1.1.2)
|
13
|
+
quickl (0.2.0)
|
14
|
+
rack (1.2.1)
|
15
|
+
rake (0.8.7)
|
16
|
+
rcov (0.9.9)
|
17
|
+
rspec (2.4.0)
|
18
|
+
rspec-core (~> 2.4.0)
|
19
|
+
rspec-expectations (~> 2.4.0)
|
20
|
+
rspec-mocks (~> 2.4.0)
|
21
|
+
rspec-core (2.4.0)
|
22
|
+
rspec-expectations (2.4.0)
|
23
|
+
diff-lcs (~> 1.1.2)
|
24
|
+
rspec-mocks (2.4.0)
|
25
|
+
sinatra (1.1.2)
|
26
|
+
rack (~> 1.1)
|
27
|
+
tilt (~> 1.2)
|
28
|
+
tilt (1.2.2)
|
29
|
+
wlang (0.10.1)
|
30
|
+
yard (0.6.4)
|
31
|
+
|
32
|
+
PLATFORMS
|
33
|
+
ruby
|
34
|
+
|
35
|
+
DEPENDENCIES
|
36
|
+
bluecloth (~> 2.0.9)
|
37
|
+
bundler (~> 1.0)
|
38
|
+
nibjs!
|
39
|
+
quickl (~> 0.2.0)
|
40
|
+
rake (~> 0.8.7)
|
41
|
+
rcov (~> 0.9)
|
42
|
+
rspec (~> 2.4.0)
|
43
|
+
sinatra (> 0)
|
44
|
+
wlang (~> 0.10.1)
|
45
|
+
yard (~> 0.6.4)
|
data/LICENCE.js
ADDED
data/LICENCE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# The MIT Licence
|
2
|
+
|
3
|
+
Copyright (c) 2011 - Bernard Lambeau
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# NibJS
|
2
|
+
|
3
|
+
nib.js - Package and embed node.js or coffeescript libraries in the browser
|
4
|
+
|
5
|
+
nib.js is a NibJS javascript library allowing to maintain javascript/coffeescript projects
|
6
|
+
ala 'node.js' (modules, exports, require) while also targetting a web browser as execution
|
7
|
+
platform. It contains a simple packager command (nibjs) that will convert your sources to a
|
8
|
+
single and minified .js file to be embedded in the browser. Node.js's exports and require
|
9
|
+
are correctly bounded.
|
10
|
+
|
11
|
+
## Getting started
|
12
|
+
|
13
|
+
gem install nibjs
|
14
|
+
nibjs --help
|
15
|
+
|
16
|
+
## How to use it
|
17
|
+
|
18
|
+
Let assume that your project has the structure below.
|
19
|
+
|
20
|
+
mylib/
|
21
|
+
dist/
|
22
|
+
src/
|
23
|
+
foo.[js,coffee] # exports.Foo = ...
|
24
|
+
bar.[js,coffee] # require('./foo')
|
25
|
+
index.[js,coffee] # exports.X = ...
|
26
|
+
spec/
|
27
|
+
foo_spec.[js,coffee]
|
28
|
+
bar_spec.[js,coffee]
|
29
|
+
package.json
|
30
|
+
|
31
|
+
### EXAMPLE 1 (embedded javascript):
|
32
|
+
|
33
|
+
In a shell:
|
34
|
+
|
35
|
+
# if the sources are .js
|
36
|
+
nibjs --libname=mylib --output=mylib.js src
|
37
|
+
|
38
|
+
# if the sources are .coffee
|
39
|
+
nibjs --coffee --libname=mylib --output=mylib.js src
|
40
|
+
|
41
|
+
In the browser:
|
42
|
+
|
43
|
+
<script src="js/nibjs.js" type="text/javascript">
|
44
|
+
<script src="js/mylib.js" type="text/javascript">
|
45
|
+
<script>
|
46
|
+
var mylib = NibJS.require('mylib')
|
47
|
+
</script>
|
48
|
+
|
49
|
+
### EXAMPLE 2 (embedded coffeescript):
|
50
|
+
|
51
|
+
In a shell:
|
52
|
+
|
53
|
+
nibjs --coffee --no-coffee-compile --libname=mylib --output=mylib.coffee src
|
54
|
+
|
55
|
+
In the browser:
|
56
|
+
|
57
|
+
<script src="js/coffee-script.js" type="text/javascript">
|
58
|
+
<script src="js/nibjs.js" type="text/javascript">
|
59
|
+
<script src="js/mylib.coffee" type="text/coffeescript">
|
60
|
+
<script>
|
61
|
+
/* But be warned of coffeescript's issue 1054
|
62
|
+
https://github.com/jashkenas/coffee-script/issues/#issue/1054 */
|
63
|
+
var mylib = NibJS.require('mylib')
|
64
|
+
</script>
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
begin
|
2
|
+
gem "bundler", "~> 1.0"
|
3
|
+
require "bundler/setup"
|
4
|
+
rescue LoadError => ex
|
5
|
+
puts ex.message
|
6
|
+
abort "Bundler failed to load, (did you run 'gem install bundler' ?)"
|
7
|
+
end
|
8
|
+
|
9
|
+
# Runs a command, returns result on STDOUT. If the exit status was no 0,
|
10
|
+
# a RuntimeError is raised.
|
11
|
+
def shell_safe_exec(cmd)
|
12
|
+
puts cmd
|
13
|
+
unless system(cmd)
|
14
|
+
raise RuntimeError, "Error while executing #{cmd}"
|
15
|
+
end
|
16
|
+
$?
|
17
|
+
end
|
18
|
+
|
19
|
+
def _(path)
|
20
|
+
File.join(File.dirname(__FILE__), path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def dist(target)
|
24
|
+
shell_safe_exec("cat src/nibjs.coffee | coffee --bare --compile --stdio > #{target}")
|
25
|
+
code = ""
|
26
|
+
code += File.read("LICENCE.js")
|
27
|
+
code += "(function(exports){\n"
|
28
|
+
code += File.read(target).gsub(/^/m, " ")
|
29
|
+
code += "}).call(this, this)"
|
30
|
+
File.open(target, "w"){|io| io << code}
|
31
|
+
end
|
32
|
+
|
33
|
+
def nibjs(*args)
|
34
|
+
nibjs = _('bin/nibjs')
|
35
|
+
shell_safe_exec "#{nibjs} #{args.flatten.join(' ')}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Dynamically load the gem spec
|
39
|
+
$gemspec_file = File.expand_path('../nibjs.gemspec', __FILE__)
|
40
|
+
$gemspec = Kernel.eval(File.read($gemspec_file))
|
41
|
+
|
42
|
+
# We run tests by default
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
#
|
46
|
+
# Install all tasks found in tasks folder
|
47
|
+
#
|
48
|
+
# See .rake files there for complete documentation.
|
49
|
+
#
|
50
|
+
Dir["tasks/*.rake"].each do |taskfile|
|
51
|
+
instance_eval File.read(taskfile), taskfile
|
52
|
+
end
|
53
|
+
|
data/bin/nibjs
ADDED
data/lib/nibjs/loader.rb
ADDED
data/lib/nibjs/main.rb
ADDED
@@ -0,0 +1,288 @@
|
|
1
|
+
require 'nibjs'
|
2
|
+
module NibJS
|
3
|
+
#
|
4
|
+
# nibjs - Package and embed node.js/coffeescript application in your browser
|
5
|
+
#
|
6
|
+
# SYNOPSIS
|
7
|
+
# #{program_name} [--help] [--version] [FOLDER]
|
8
|
+
#
|
9
|
+
# OPTIONS
|
10
|
+
# #{summarized_options}
|
11
|
+
#
|
12
|
+
# DESCRIPTION
|
13
|
+
# This command packages a complete javascript/coffeescript as a single .js file
|
14
|
+
# to be embedded in the browser. Basically, it defines Node.js's exports and
|
15
|
+
# require to work nicely. For this, we expect a project structure that respect
|
16
|
+
# Node.js's package conventions (exports, require, index):
|
17
|
+
#
|
18
|
+
# mylib/
|
19
|
+
# dist/
|
20
|
+
# src/
|
21
|
+
# foo.[js,coffee] # exports.Foo = ...
|
22
|
+
# bar.[js,coffee] # require('./foo')
|
23
|
+
# index.[js,coffee] # exports.X = ...
|
24
|
+
# spec/
|
25
|
+
# foo_spec.[js,coffee]
|
26
|
+
# bar_spec.[js,coffee]
|
27
|
+
#
|
28
|
+
# EXAMPLE 1 (embedded javascript):
|
29
|
+
#
|
30
|
+
# In a shell:
|
31
|
+
#
|
32
|
+
# # if the sources are .js
|
33
|
+
# nibjs --libname=mylib --output=mylib.js src
|
34
|
+
#
|
35
|
+
# # if the sources are .coffee
|
36
|
+
# nibjs --coffee --libname=mylib --output=mylib.js src
|
37
|
+
#
|
38
|
+
# In the browser:
|
39
|
+
#
|
40
|
+
# <script src="js/coffee-script.js" type="text/javascript">
|
41
|
+
# <script src="js/nibjs.js" type="text/javascript">
|
42
|
+
# <script src="js/mylib.js" type="text/javascript">
|
43
|
+
# <script>
|
44
|
+
# var mylib = NibJS.require('mylib')
|
45
|
+
# </script>
|
46
|
+
#
|
47
|
+
# EXAMPLE 2 (embedded coffeescript):
|
48
|
+
#
|
49
|
+
# In a shell:
|
50
|
+
#
|
51
|
+
# nibjs --coffee --no-coffee-compile --libname=mylib --output=mylib.coffee src
|
52
|
+
#
|
53
|
+
# In the browser:
|
54
|
+
#
|
55
|
+
# <script src="js/nibjs.js" type="text/javascript">
|
56
|
+
# <script src="js/mylib.coffee" type="text/coffeescript">
|
57
|
+
# <script>
|
58
|
+
# /* But be warned of coffeescript's issue 1054
|
59
|
+
# https://github.com/jashkenas/coffee-script/issues/#issue/1054 */
|
60
|
+
# var mylib = NibJS.require('mylib')
|
61
|
+
# </script>
|
62
|
+
#
|
63
|
+
class Main < Quickl::Command(__FILE__, __LINE__)
|
64
|
+
|
65
|
+
# Name of the library which is packaged
|
66
|
+
attr_accessor :libname
|
67
|
+
|
68
|
+
# Look for .coffee files
|
69
|
+
attr_accessor :coffee
|
70
|
+
|
71
|
+
# Compile .coffee files
|
72
|
+
attr_accessor :coffee_compile
|
73
|
+
|
74
|
+
# Join the sources instead of treating them separately
|
75
|
+
attr_accessor :join
|
76
|
+
|
77
|
+
# Invoke ugligyjs on result
|
78
|
+
attr_accessor :uglify
|
79
|
+
|
80
|
+
# Add 'libname = NibJS.require(libname)' at end of script
|
81
|
+
attr_accessor :autorequire
|
82
|
+
|
83
|
+
# Path to a licencing file to add as header
|
84
|
+
attr_accessor :header
|
85
|
+
|
86
|
+
# IO or filename where to output result
|
87
|
+
attr_accessor :output
|
88
|
+
|
89
|
+
def initialize
|
90
|
+
@output = STDOUT
|
91
|
+
end
|
92
|
+
|
93
|
+
# Install options
|
94
|
+
options do |opt|
|
95
|
+
@libname = nil
|
96
|
+
opt.on("--libname=X", "Specify the main library name") do |value|
|
97
|
+
@libname = value
|
98
|
+
end
|
99
|
+
@autorequire = false
|
100
|
+
opt.on('-a','--autorequire', "Add 'libname = NibJS.require(libname)' at end of script") do
|
101
|
+
@autorequire = true
|
102
|
+
end
|
103
|
+
@coffee = false
|
104
|
+
opt.on("-c", "--coffee", "Look for .coffee instead of .js files (requires coffee)") do
|
105
|
+
@coffee = true
|
106
|
+
end
|
107
|
+
@coffee_compile = true
|
108
|
+
opt.on("--[no-]coffee-compile", "Compile .coffee sources to javascript (requires coffee)") do |value|
|
109
|
+
@coffee_compile = value
|
110
|
+
end
|
111
|
+
@join = false
|
112
|
+
opt.on('-j', '--join', "Join the sources instead of treating them separately") do |value|
|
113
|
+
@join = true
|
114
|
+
end
|
115
|
+
@uglify = false
|
116
|
+
opt.on('-u', '--[no-]uglify', "Invoke ugligyjs on result (requires uglifyjs)") do |value|
|
117
|
+
@uglify = value
|
118
|
+
end
|
119
|
+
opt.separator('')
|
120
|
+
@header = nil
|
121
|
+
opt.on("--header=FILE", "Add a (licencing) header from a file") do |value|
|
122
|
+
@header = value
|
123
|
+
end
|
124
|
+
#@output = STDOUT
|
125
|
+
opt.on("-o", "--output=FILE", "Output in a specific file") do |value|
|
126
|
+
@output = value
|
127
|
+
end
|
128
|
+
opt.on_tail("--help", "Show help") do
|
129
|
+
raise Quickl::Help
|
130
|
+
end
|
131
|
+
opt.on_tail("--version", "Show version") do
|
132
|
+
raise Quickl::Exit, "#{program_name} #{NibJS::VERSION} (c) 2011, Bernard Lambeau"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
### In coffee
|
137
|
+
|
138
|
+
def with_coffee_registration(file)
|
139
|
+
code = ""
|
140
|
+
code += "nibjs.register '#{file}', (exports, require)->\n"
|
141
|
+
code += yield.strip.gsub(/^/m, ' ') + "\n"
|
142
|
+
code += "\n"
|
143
|
+
end
|
144
|
+
|
145
|
+
def with_coffee_define(package)
|
146
|
+
code = ""
|
147
|
+
code += "NibJS.define '#{package}', (nibjs)->\n"
|
148
|
+
code += yield.strip.gsub(/^/m, ' ') + "\n"
|
149
|
+
code += "\n"
|
150
|
+
code += " nibjs.require './index'\n"
|
151
|
+
end
|
152
|
+
|
153
|
+
### In javascript
|
154
|
+
|
155
|
+
def with_js_registration(file)
|
156
|
+
code = ""
|
157
|
+
code += "nibjs.register('#{file}', function(exports, require) {\n"
|
158
|
+
code += yield.strip.gsub(/^/m, ' ') + "\n"
|
159
|
+
code += "});\n"
|
160
|
+
end
|
161
|
+
|
162
|
+
def with_js_define(package)
|
163
|
+
code = ""
|
164
|
+
code += "NibJS.define('#{package}', function(nibjs) {\n"
|
165
|
+
code += yield.strip.gsub(/^/m, ' ') + "\n"
|
166
|
+
code += " return nibjs.require('./index');\n"
|
167
|
+
code += "});\n"
|
168
|
+
end
|
169
|
+
|
170
|
+
###
|
171
|
+
|
172
|
+
# Runs a command, returns result on STDOUT. If the exit status was no 0,
|
173
|
+
# a RuntimeError is raised.
|
174
|
+
def safe_run(cmd)
|
175
|
+
res = `#{cmd}`
|
176
|
+
unless $?.exitstatus == 0
|
177
|
+
raise RuntimeError, "Error while executing #{cmd}"
|
178
|
+
end
|
179
|
+
res
|
180
|
+
end
|
181
|
+
|
182
|
+
def with_temp_file(content)
|
183
|
+
require "tempfile"
|
184
|
+
file = Tempfile.new('nibjs')
|
185
|
+
file << content
|
186
|
+
file.close
|
187
|
+
res = yield(file)
|
188
|
+
file.unlink
|
189
|
+
res
|
190
|
+
end
|
191
|
+
|
192
|
+
###
|
193
|
+
|
194
|
+
def file2require(root_folder, file)
|
195
|
+
root_folder, file = File.expand_path(root_folder), File.expand_path(file)
|
196
|
+
stripped = file[(1+root_folder.size)..-1]
|
197
|
+
stripped =~ /(.*)\.(js|coffee)$/
|
198
|
+
"./#{$1}"
|
199
|
+
end
|
200
|
+
|
201
|
+
###
|
202
|
+
|
203
|
+
def collect_on_files(folder)
|
204
|
+
files = if coffee
|
205
|
+
Dir["#{folder}/**/*.coffee"]
|
206
|
+
else
|
207
|
+
Dir["#{folder}/**/*.js"]
|
208
|
+
end
|
209
|
+
if join
|
210
|
+
files.sort!
|
211
|
+
content = files.collect{|f| File.read(f)}.join("\n")
|
212
|
+
[ with_temp_file(content){|f| yield(f.path, './index')} ]
|
213
|
+
else
|
214
|
+
files.collect{|f| yield(f, file2require(folder, f))}
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def compile_coffee_source(code)
|
219
|
+
with_temp_file(code){|f|
|
220
|
+
safe_run("cat #{f.path} | coffee --compile --stdio --bare")
|
221
|
+
}
|
222
|
+
end
|
223
|
+
|
224
|
+
def compile(folder)
|
225
|
+
folder = File.expand_path(folder)
|
226
|
+
self.libname ||= File.basename(folder)
|
227
|
+
if self.libname =~ /(.*)\.\w/
|
228
|
+
self.libname = $1
|
229
|
+
end
|
230
|
+
|
231
|
+
code = if coffee
|
232
|
+
code = with_coffee_define(libname){
|
233
|
+
collect_on_files(folder){|filepath, reqname|
|
234
|
+
with_coffee_registration(reqname){ File.read(filepath) }
|
235
|
+
}.join
|
236
|
+
}
|
237
|
+
if coffee_compile
|
238
|
+
compile_coffee_source(code)
|
239
|
+
else
|
240
|
+
code
|
241
|
+
end
|
242
|
+
else
|
243
|
+
with_js_define(libname){
|
244
|
+
collect_on_files(folder){|filepath, reqname|
|
245
|
+
with_js_registration(reqname){ File.read(filepath) }
|
246
|
+
}.join
|
247
|
+
}
|
248
|
+
end
|
249
|
+
|
250
|
+
# Add the autorequire line if requested
|
251
|
+
if autorequire
|
252
|
+
if (!coffee || coffee_compile)
|
253
|
+
code += "var #{libname} = NibJS.require('#{libname}');\n"
|
254
|
+
else
|
255
|
+
code += "#{libname} = NibJS.require '#{libname}'\n"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
if header
|
260
|
+
code = File.read(header) + "\n" + code
|
261
|
+
end
|
262
|
+
|
263
|
+
# Uglify result now
|
264
|
+
if uglify
|
265
|
+
code = with_temp_file(code){|f| safe_run("uglifyjs #{f.path}") }
|
266
|
+
end
|
267
|
+
|
268
|
+
code
|
269
|
+
end
|
270
|
+
|
271
|
+
def with_output
|
272
|
+
if String === output
|
273
|
+
File.open(output, 'w'){|io| yield(io) }
|
274
|
+
else
|
275
|
+
yield(output)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def execute(args)
|
280
|
+
if args.size == 1
|
281
|
+
with_output{|io| io << compile(args[0]) }
|
282
|
+
else
|
283
|
+
raise Quickl::Help
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
end # class Main
|
288
|
+
end # module NibJS
|