flok 0.0.20 → 0.0.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/flok +42 -2
- data/docs/project.md +1 -0
- data/flok.gemspec +2 -0
- data/lib/flok/version.rb +1 -1
- data/spec/etc/cli_spec.rb +234 -69
- data/spec/lib/helpers.rb +32 -21
- metadata +29 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bdd0e73ce51527ed47bbeb40ec3f891488f4265
|
4
|
+
data.tar.gz: 692562bb5786d8cd4c03a74db6aa3954b8f64955
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35d8ce34aa667a0d0d5c840e50ae4531167b67af3561057e0ab13a807a061e3af93ea6366dd308290958977e26cdf930ab8165c02fb755e150e2dfe1265c3bf4
|
7
|
+
data.tar.gz: 9698f5d86ba29a377308a4ab414744ad466959115dab251dc102f0a11337def7ef0e1c9d468ae6b1c7a96db190e1104dd34c01dde9052ef2d44ca6181453a8e7
|
data/bin/flok
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'flok'
|
4
4
|
require 'thor'
|
5
5
|
require 'fileutils'
|
6
|
+
require 'webrick'
|
7
|
+
require_relative '../spec/lib/helpers.rb'
|
6
8
|
|
7
9
|
class FlokCLI < Thor
|
8
10
|
desc "new <path>", "Create a new flok project and/or module, you may supply an absolute path or relative, the last entry in the path will be the module name and folder name of the project"
|
@@ -61,11 +63,49 @@ class FlokCLI < Thor
|
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
|
-
desc "server", "Monitors for changes within your flok application and triggers an automatic rebuild of ./products/* for a PLATFORM"
|
66
|
+
desc "server", "Monitors for changes within your flok application and triggers an automatic rebuild of ./products/* for a PLATFORM when something in ./app changes"
|
67
|
+
include SpecHelpers #Contains sh2
|
65
68
|
def server platform
|
66
|
-
|
69
|
+
File.write "Guardfile", %{
|
70
|
+
guard :shell, :all_on_start => true do
|
71
|
+
watch %r{^app/.*} do |m|
|
72
|
+
system("#{$0} build #{platform}")
|
73
|
+
res = system("#{$0} build #{platform}");
|
74
|
+
$stdout.puts "BUILD RAN"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
}
|
78
|
+
|
79
|
+
#Ensure puts does something because it's on another thread
|
80
|
+
$stdout.sync = true
|
81
|
+
|
82
|
+
###########################################################################
|
83
|
+
#We execute two tasks that run at the same time, (1) the webrick hoster
|
84
|
+
#and (2) the guard reloader that triggers build
|
85
|
+
###########################################################################
|
86
|
+
#1) Launch webrick server
|
87
|
+
server = WEBrick::HTTPServer.new :Port => 9992, :DocumentRoot => "./products/#{platform}", :StartCallback => Proc.new {
|
88
|
+
}
|
89
|
+
server_started = false
|
90
|
+
|
91
|
+
#2) Wait for initial build to launch (all_on_start)
|
92
|
+
sh2("guard") do |inp, out|
|
93
|
+
loop do
|
94
|
+
res = out.readline
|
95
|
+
if res =~ /BUILD RAN/
|
96
|
+
#Start server
|
97
|
+
Thread.new { server.start } unless server_started
|
98
|
+
server_started = true
|
99
|
+
|
100
|
+
puts "BUILD RAN"
|
101
|
+
else
|
102
|
+
$stderr.puts res
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
67
106
|
end
|
68
107
|
|
108
|
+
#Part of the build command
|
69
109
|
class ERBUserApplicationContext
|
70
110
|
def get_binding
|
71
111
|
return binding
|
data/docs/project.md
CHANGED
@@ -6,6 +6,7 @@ You create and build projects via the `flok` command.
|
|
6
6
|
|
7
7
|
* `flok new <path>` - Create a new flok project
|
8
8
|
* `flok build <platform>` - Build a flok project. Generates files in `./products`
|
9
|
+
* `flok server <platform>` - Trigger auto-rebuild when a file is modified in the `./app` folder and hosts the `products/$PLATFORM` folder on `http://localhost:9992/`. e.g. `http://localhost:9992/application_user.js`
|
9
10
|
|
10
11
|
###Folder structure
|
11
12
|
* `app/`
|
data/flok.gemspec
CHANGED
@@ -33,5 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_runtime_dependency "thor", "~> 0.19"
|
34
34
|
spec.add_runtime_dependency "rake", "~> 10.3"
|
35
35
|
spec.add_runtime_dependency "therubyracer", "~> 0.12"
|
36
|
+
spec.add_runtime_dependency "guard", "~> 2.1"
|
37
|
+
spec.add_runtime_dependency "guard-shell", "~> 0.7"
|
36
38
|
spec.executables << 'flok'
|
37
39
|
end
|
data/lib/flok/version.rb
CHANGED
data/spec/etc/cli_spec.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
Dir.chdir File.join File.dirname(__FILE__), '../../'
|
2
2
|
require './spec/env/etc'
|
3
3
|
require './lib/flok'
|
4
|
+
require './spec/lib/helpers.rb'
|
5
|
+
require './spec/lib/rspec_extensions.rb'
|
4
6
|
|
5
7
|
require 'tempfile'
|
6
8
|
require 'securerandom'
|
@@ -29,89 +31,252 @@ def flok_new
|
|
29
31
|
end
|
30
32
|
|
31
33
|
RSpec.describe "CLI" do
|
32
|
-
it "Can create a new project with correct directories" do
|
33
|
-
flok_new do
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
template_nodes = nil
|
38
|
-
Dir.chdir File.join(File.dirname(__FILE__), "../../lib/flok/project_template") do
|
39
|
-
template_nodes = Dir["**/*"].map{|e| e.gsub(/\.erb$/i, "")}
|
40
|
-
end
|
41
|
-
new_proj_nodes = Dir["**/*"]
|
42
|
-
|
43
|
-
expect(new_proj_nodes).to eq(template_nodes)
|
34
|
+
# it "Can create a new project with correct directories" do
|
35
|
+
#flok_new do
|
36
|
+
##Should include all entities in the project template with the exception
|
37
|
+
##of erb extenseded entities (which will still be included, but they each
|
38
|
+
##will not have the erb ending
|
39
|
+
#template_nodes = nil
|
40
|
+
#Dir.chdir File.join(File.dirname(__FILE__), "../../lib/flok/project_template") do
|
41
|
+
#template_nodes = Dir["**/*"].map{|e| e.gsub(/\.erb$/i, "")}
|
42
|
+
#end
|
43
|
+
#new_proj_nodes = Dir["**/*"]
|
44
|
+
#$stderr.puts "Flok version = #{Flok::VERSION}"
|
45
|
+
#expect(new_proj_nodes).to eq(template_nodes)
|
44
46
|
|
45
|
-
expect(files).to include("Gemfile")
|
46
|
-
end
|
47
|
-
end
|
47
|
+
#expect(files).to include("Gemfile")
|
48
|
+
#end
|
49
|
+
#end
|
50
|
+
|
51
|
+
#it "Can build a project with every type of platform" do
|
52
|
+
#Flok.platforms.each do |platform|
|
53
|
+
#flok_new do
|
54
|
+
##Build a new project
|
55
|
+
#flok "build #{platform}"
|
56
|
+
|
57
|
+
##Check it's products directory
|
58
|
+
#expect(dirs).to include "products"
|
59
|
+
#Dir.chdir "products" do
|
60
|
+
##Has a platform folder
|
61
|
+
#expect(dirs).to include platform
|
62
|
+
#Dir.chdir platform do
|
63
|
+
##Has an application_user.js file
|
64
|
+
#expect(files).to include "application_user.js"
|
65
|
+
|
66
|
+
##The application_user.js contains both the glob/application.js and the glob/user_compiler.js
|
67
|
+
#glob_application_js = File.read('glob/application.js')
|
68
|
+
#glob_user_compiler_js = File.read('glob/user_compiler.js')
|
69
|
+
#application_user_js = File.read('application_user.js')
|
70
|
+
#expect(application_user_js).to include(glob_application_js)
|
71
|
+
#expect(application_user_js).to include(glob_user_compiler_js)
|
72
|
+
|
73
|
+
##Contains the same files as the kernel in the drivers directory
|
74
|
+
#expect(dirs).to include "drivers"
|
75
|
+
#end
|
76
|
+
#end
|
77
|
+
#end
|
78
|
+
#end
|
79
|
+
#end
|
80
|
+
|
81
|
+
#it "Can build a project with a controller file for each platform" do
|
82
|
+
##Compile and then return the length of the application_user.js file
|
83
|
+
#def compile_with_file path=nil
|
84
|
+
##Custom controller to test source with
|
85
|
+
#controller_src = File.read(path) if path
|
86
|
+
#flok_new do
|
87
|
+
#File.write "./app/controllers/controller0.rb", controller_src if path
|
88
|
+
|
89
|
+
##Build a new project
|
90
|
+
#flok "build #{@platform}"
|
91
|
+
|
92
|
+
##Check it's products directory
|
93
|
+
#Dir.chdir "products" do
|
94
|
+
##Has a platform folder
|
95
|
+
#Dir.chdir @platform do
|
96
|
+
#glob_application_js = File.read('glob/application.js')
|
97
|
+
#glob_user_compiler_js = File.read('glob/user_compiler.js')
|
98
|
+
#application_user_js = File.read('application_user.js')
|
99
|
+
|
100
|
+
#return application_user_js.split("\n").count
|
101
|
+
#end
|
102
|
+
#end
|
103
|
+
#end
|
104
|
+
#end
|
105
|
+
|
106
|
+
#Flok.platforms.each do |platform|
|
107
|
+
#@platform = platform
|
108
|
+
#controller_rb = File.read('./spec/etc/user_compiler/controller0.rb')
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
##The file with content should be longer when compiled into the flat application_user.js
|
113
|
+
#len_with_content = compile_with_file "./spec/etc/user_compiler/controller0.rb"
|
114
|
+
#len_no_content = compile_with_file
|
115
|
+
|
116
|
+
#expect(len_no_content).to be < len_with_content
|
117
|
+
#end
|
118
|
+
#end
|
119
|
+
|
120
|
+
include SpecHelpers
|
121
|
+
# it "server does build project when first run" do
|
122
|
+
#Flok.platforms.each do |platform|
|
123
|
+
#flok_new do
|
124
|
+
##Start the server
|
125
|
+
##Get path to the flok binary relative to this file
|
126
|
+
#bin_path = File.join(File.dirname(__FILE__), "../../bin/flok")
|
127
|
+
#lib_path = File.join(File.dirname(__FILE__), "../../lib")
|
128
|
+
|
129
|
+
##Now execute the command with a set of arguments
|
130
|
+
#sh2("ruby -I#{lib_path} #{bin_path} server #{platform}", /BUILD RAN/) do |inp, out|
|
131
|
+
##The server should always trigger a build on it's first run
|
132
|
+
#expect(dirs).to include "products"
|
133
|
+
#Dir.chdir "products" do
|
134
|
+
##Has a platform folder
|
135
|
+
#expect(dirs).to include platform
|
136
|
+
#Dir.chdir platform do
|
137
|
+
##Has an application_user.js file
|
138
|
+
#expect(files).to include "application_user.js"
|
139
|
+
|
140
|
+
##The application_user.js contains both the glob/application.js and the glob/user_compiler.js
|
141
|
+
#glob_application_js = File.read('glob/application.js')
|
142
|
+
#glob_user_compiler_js = File.read('glob/user_compiler.js')
|
143
|
+
#application_user_js = File.read('application_user.js')
|
144
|
+
#expect(application_user_js).to include(glob_application_js)
|
145
|
+
#expect(application_user_js).to include(glob_user_compiler_js)
|
48
146
|
|
49
|
-
|
147
|
+
##Contains the same files as the kernel in the drivers directory
|
148
|
+
#expect(dirs).to include "drivers"
|
149
|
+
#end
|
150
|
+
#end
|
151
|
+
#end
|
152
|
+
#end
|
153
|
+
#end
|
154
|
+
#end
|
155
|
+
|
156
|
+
#it "server does rebuild project when a file is added" do
|
157
|
+
#Flok.platforms.each do |platform|
|
158
|
+
#flok_new do
|
159
|
+
##Start the server
|
160
|
+
##Get path to the flok binary relative to this file
|
161
|
+
#bin_path = File.join(File.dirname(__FILE__), "../../bin/flok")
|
162
|
+
#lib_path = File.join(File.dirname(__FILE__), "../../lib")
|
163
|
+
|
164
|
+
##Now execute the command with a set of arguments
|
165
|
+
#sh2("ruby -I#{lib_path} #{bin_path} server #{platform}", /BUILD RAN/) do |inp, out|
|
166
|
+
##Get the original build
|
167
|
+
#application_user_js = File.read("products/#{platform}/application_user.js")
|
168
|
+
|
169
|
+
##Now add a file
|
170
|
+
#File.write "./app/controllers/test2.rb", %{
|
171
|
+
#controller "my_controller" do
|
172
|
+
#view "my_controller"
|
173
|
+
#action "my_action" do
|
174
|
+
#on_entry %{
|
175
|
+
#}
|
176
|
+
#end
|
177
|
+
#end
|
178
|
+
#}
|
179
|
+
|
180
|
+
##Wait for a rebuild
|
181
|
+
#expect(out).to readline_and_equal_x_within_y_seconds("BUILD RAN", 5.seconds)
|
182
|
+
|
183
|
+
##Get updated version
|
184
|
+
#application_user_js2 = File.read("products/#{platform}/application_user.js")
|
185
|
+
|
186
|
+
##Make sure the compiled file is different and it's somewhat valid (length > 30)
|
187
|
+
#expect(application_user_js2).not_to eq(application_user_js)
|
188
|
+
#expect(application_user_js2.length).to be > 30 #Magic 30 to avoid any problems
|
189
|
+
#end
|
190
|
+
#end
|
191
|
+
#end
|
192
|
+
#end
|
193
|
+
|
194
|
+
it "server does delete existing products when a file is added (before it does a rebuild, i.e. clean)" do
|
50
195
|
Flok.platforms.each do |platform|
|
51
196
|
flok_new do
|
52
|
-
#
|
53
|
-
flok
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
197
|
+
#Start the server
|
198
|
+
#Get path to the flok binary relative to this file
|
199
|
+
bin_path = File.join(File.dirname(__FILE__), "../../bin/flok")
|
200
|
+
lib_path = File.join(File.dirname(__FILE__), "../../lib")
|
201
|
+
|
202
|
+
#Now execute the command with a set of arguments
|
203
|
+
sh2("ruby -I#{lib_path} #{bin_path} server #{platform}", /BUILD RAN/) do |inp, out|
|
204
|
+
#Get the original build
|
205
|
+
application_user_js = File.read("products/#{platform}/application_user.js")
|
206
|
+
|
207
|
+
#Now add a file
|
208
|
+
File.write "./app/controllers/test2.rb", %{
|
209
|
+
controller "my_controller" do
|
210
|
+
view "my_controller"
|
211
|
+
action "my_action" do
|
212
|
+
on_entry %{
|
213
|
+
}
|
214
|
+
end
|
215
|
+
end
|
216
|
+
}
|
217
|
+
|
218
|
+
#DONT Wait for a rebuild
|
219
|
+
is_dir = File.directory?("products/#{platform}")
|
220
|
+
expect(is_dir).to eq(false)
|
74
221
|
end
|
75
222
|
end
|
76
223
|
end
|
77
224
|
end
|
78
225
|
|
79
|
-
it "
|
80
|
-
#
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
File.
|
226
|
+
#it "server does host products on localhost:9992" do
|
227
|
+
#Flok.platforms.each do |platform|
|
228
|
+
#flok_new do
|
229
|
+
##Start the server
|
230
|
+
##Get path to the flok binary relative to this file
|
231
|
+
#bin_path = File.join(File.dirname(__FILE__), "../../bin/flok")
|
232
|
+
#lib_path = File.join(File.dirname(__FILE__), "../../lib")
|
86
233
|
|
87
|
-
|
88
|
-
|
234
|
+
##Now execute the command with a set of arguments
|
235
|
+
#sh2("ruby -I#{lib_path} #{bin_path} server #{platform}", /BUILD RAN/) do |inp, out|
|
236
|
+
#real_application_user_js = File.read("products/#{platform}/application_user.js")
|
89
237
|
|
90
|
-
|
91
|
-
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
238
|
+
##Grab the application_user.js file
|
239
|
+
#res = wget "http://localhost:9992/application_user.js"
|
240
|
+
#expect(res).to eq(real_application_user_js)
|
241
|
+
#end
|
242
|
+
#end
|
243
|
+
#end
|
244
|
+
#end
|
97
245
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
246
|
+
#it "server does host products on localhost:9992 and changes the products when the files change" do
|
247
|
+
#Flok.platforms.each do |platform|
|
248
|
+
#flok_new do
|
249
|
+
##Start the server
|
250
|
+
##Get path to the flok binary relative to this file
|
251
|
+
#bin_path = File.join(File.dirname(__FILE__), "../../bin/flok")
|
252
|
+
#lib_path = File.join(File.dirname(__FILE__), "../../lib")
|
103
253
|
|
104
|
-
|
105
|
-
|
106
|
-
|
254
|
+
##Now execute the command with a set of arguments
|
255
|
+
#sh2("ruby -I#{lib_path} #{bin_path} server #{platform}", /BUILD RAN/) do |inp, out|
|
256
|
+
##Get the original
|
257
|
+
#application_user_js = wget "http://localhost:9992/application_user.js"
|
107
258
|
|
108
|
-
|
259
|
+
##Now add a file
|
260
|
+
#File.write "./app/controllers/test2.rb", %{
|
261
|
+
#controller "my_controller" do
|
262
|
+
#view "my_controller"
|
263
|
+
#action "my_action" do
|
264
|
+
#on_entry %{
|
265
|
+
#}
|
266
|
+
#end
|
267
|
+
#end
|
268
|
+
#}
|
269
|
+
##Wait for a rebuild
|
270
|
+
#expect(out).to readline_and_equal_x_within_y_seconds("BUILD RAN", 5.seconds)
|
109
271
|
|
110
|
-
|
111
|
-
|
112
|
-
len_no_content = compile_with_file
|
272
|
+
##Grab new version
|
273
|
+
#application_user_js2 = wget "http://localhost:9992/application_user.js"
|
113
274
|
|
114
|
-
|
115
|
-
|
116
|
-
|
275
|
+
##Make sure the compiled file is different and it's somewhat valid (length > 30)
|
276
|
+
#expect(application_user_js2).not_to eq(application_user_js)
|
277
|
+
#expect(application_user_js2.length).to be > 30 #Magic 30 to avoid any problems
|
278
|
+
#end
|
279
|
+
#end
|
280
|
+
#end
|
281
|
+
#end
|
117
282
|
end
|
data/spec/lib/helpers.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'securerandom'
|
2
2
|
require 'json'
|
3
3
|
require 'webrick'
|
4
|
+
require 'open-uri'
|
4
5
|
|
5
6
|
#Duplex pipe
|
6
7
|
###################################################################################################################
|
@@ -290,29 +291,39 @@ def sh2 *args
|
|
290
291
|
end
|
291
292
|
end
|
292
293
|
|
293
|
-
#Execute some chrome code
|
294
|
-
def chrome code, wait_for
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
294
|
+
#Execute some chrome code
|
295
|
+
def chrome code, wait_for
|
296
|
+
#Load js assets
|
297
|
+
js_assets = Dir["./spec/assets/*.js"]
|
298
|
+
f = Tempfile.new(SecureRandom.hex)
|
299
|
+
js_assets.each do |fn|
|
300
|
+
f.puts File.read(fn)
|
301
|
+
end
|
301
302
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
303
|
+
f.puts code
|
304
|
+
f.close
|
305
|
+
sh "boojs", f.path, wait_for do
|
306
|
+
yield
|
307
|
+
end
|
306
308
|
end
|
307
|
-
end
|
308
309
|
|
309
|
-
#Get the result at an endpoint
|
310
|
-
def get endpoint
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
310
|
+
#Get the result at an endpoint
|
311
|
+
def get endpoint
|
312
|
+
uri = URI.parse(endpoint)
|
313
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
314
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
315
|
+
response = http.request(request)
|
315
316
|
|
316
|
-
|
317
|
-
end
|
317
|
+
return JSON.parse(response.body)
|
318
|
+
end
|
319
|
+
|
320
|
+
def wget endpoint
|
321
|
+
begin
|
322
|
+
Timeout::timeout(5) do
|
323
|
+
return open(endpoint).read
|
324
|
+
end
|
325
|
+
rescue Timeout::Error
|
326
|
+
raise "Timed out while waiting for: #{endpoint.inspect}"
|
327
|
+
end
|
328
|
+
end
|
318
329
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flok
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- seo
|
@@ -220,6 +220,34 @@ dependencies:
|
|
220
220
|
- - "~>"
|
221
221
|
- !ruby/object:Gem::Version
|
222
222
|
version: '0.12'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: guard
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - "~>"
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '2.1'
|
230
|
+
type: :runtime
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - "~>"
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '2.1'
|
237
|
+
- !ruby/object:Gem::Dependency
|
238
|
+
name: guard-shell
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
240
|
+
requirements:
|
241
|
+
- - "~>"
|
242
|
+
- !ruby/object:Gem::Version
|
243
|
+
version: '0.7'
|
244
|
+
type: :runtime
|
245
|
+
prerelease: false
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
247
|
+
requirements:
|
248
|
+
- - "~>"
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: '0.7'
|
223
251
|
description: Flok is a cross-platform application framework system that exports javascript
|
224
252
|
files
|
225
253
|
email:
|