browser_app_base 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf40fc8ffcf491a1fba31012f2e8e3aba1089dc14a8de381f420b33a51d2ca3a
4
- data.tar.gz: 3279233418b767f81a01350e5eb27f102f84f7b2c791d784ca0d25f8c58508c7
3
+ metadata.gz: d8f803f44d98065ce973ec89c418d7d9d8fb75ce8c1f6dc74f8e449681a3a0f5
4
+ data.tar.gz: 0bf164a5280e040b5efa5fe0221ae17f19d77b4569c3c4db5e4893d19a5e0efb
5
5
  SHA512:
6
- metadata.gz: d264ee2f1c8d9aed28ea36c523c400d445570fd219271eece7135655831bb02d75c1ad5e4b77eda4fbba7fdeb32ebc7986765c43cc9702e4b8a32ee1351bf199
7
- data.tar.gz: 063d377c14dca4341cf963788c3de83a6bc7a6e6ddb93c5abc0bba06f40aa1cbb01596e19b95640ca7a99c11d5b996e1226c73326d9a95305351510dfb5e1a50
6
+ metadata.gz: 881fd8551b75678a1825a1cb227918f22ce9e6db9377e940bd7b25d04d7827d491c4f42c0c4da372607666533ada91239fb4f79f3792b3252dedf3c589424de4
7
+ data.tar.gz: 1c630a5c7affe753747bc2aee0789b384249676f6a90a036fce54471084e0bf471c2c88bdd701e13851f5f7d33f53e8360a52e6898a29bc09e9f045183791b9d
data/.vscode/launch.json CHANGED
@@ -5,10 +5,16 @@
5
5
  "version": "0.2.0",
6
6
  "configurations": [
7
7
  {
8
- "name": "Debug Local File",
8
+ "name": "Debug create_browser_app.rb",
9
9
  "type": "Ruby",
10
10
  "request": "launch",
11
- "cwd": "${workspaceRoot}/lib/template/",
11
+ "program": "${workspaceRoot}/bin/create_browser_app.rb"
12
+ },
13
+ {
14
+ "name": "Debug start.rb",
15
+ "type": "Ruby",
16
+ "request": "launch",
17
+ "cwd": "${workspaceRoot}/lib/template",
12
18
  "program": "${workspaceRoot}/lib/template/start.rb"
13
19
  }
14
20
  ]
data/README.md CHANGED
@@ -73,6 +73,34 @@ ui application sample
73
73
  }
74
74
  ```
75
75
 
76
+ ## Send a message from your browser application to your ruby application
77
+
78
+ Use the send_message function
79
+
80
+ main.js sample
81
+ ```javascript
82
+ $("#exec").click(function () {
83
+ send_message("exec:" + $("#upFile").val());
84
+ });
85
+
86
+ ```
87
+
88
+ ## Send a message from the ruby application to the browser application
89
+
90
+ Use the app_send function
91
+
92
+ my_app_sample.rb sample
93
+ ```ruby
94
+ class MyApp < AppMainBase
95
+ def start(argv)
96
+ # popup message
97
+ app_send("popup:message string")
98
+
99
+ # log message
100
+ yield "log message"
101
+ end
102
+ end
103
+ ```
76
104
 
77
105
  ## Development
78
106
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BrowserAppBase
4
- VERSION = "0.0.8"
4
+ VERSION = "0.0.9"
5
5
  end
@@ -1,50 +1,50 @@
1
- [
2
- {
3
- "name": "name1",
4
- "value": "value1",
5
- "type": "input",
6
- "select": "",
7
- "description": "設定項目1"
8
- },
9
- {
10
- "name": "name2",
11
- "value": true,
12
- "type": "checkbox",
13
- "select": "",
14
- "description": "有効にする場合はチェック"
15
- },
16
- {
17
- "name": "name3",
18
- "value": "1",
19
- "type": "select",
20
- "select": [
21
- "1",
22
- "2",
23
- "3",
24
- "4",
25
- "5"
26
- ],
27
- "description": "選択項目"
28
- },
29
- {
30
- "name": "name4",
31
- "value": "value4",
32
- "type": "input",
33
- "select": "",
34
- "description": "設定項目4"
35
- },
36
- {
37
- "name": "name5",
38
- "value": "value5",
39
- "type": "input",
40
- "select": "",
41
- "description": "設定項目5"
42
- },
43
- {
44
- "name": "name6",
45
- "value": "value6",
46
- "type": "input",
47
- "select": "",
48
- "description": "設定項目6"
49
- }
50
- ]
1
+ [
2
+ {
3
+ "name": "name1",
4
+ "value": "value1",
5
+ "type": "input",
6
+ "select": "",
7
+ "description": "設定項目1"
8
+ },
9
+ {
10
+ "name": "name2",
11
+ "value": true,
12
+ "type": "checkbox",
13
+ "select": "",
14
+ "description": "有効にする場合はチェック"
15
+ },
16
+ {
17
+ "name": "name3",
18
+ "value": "1",
19
+ "type": "select",
20
+ "select": [
21
+ "1",
22
+ "2",
23
+ "3",
24
+ "4",
25
+ "5"
26
+ ],
27
+ "description": "選択項目"
28
+ },
29
+ {
30
+ "name": "name4",
31
+ "value": "value4",
32
+ "type": "input",
33
+ "select": "",
34
+ "description": "設定項目4"
35
+ },
36
+ {
37
+ "name": "name5",
38
+ "value": "value5",
39
+ "type": "input",
40
+ "select": "",
41
+ "description": "設定項目5"
42
+ },
43
+ {
44
+ "name": "name6",
45
+ "value": "value6",
46
+ "type": "input",
47
+ "select": "",
48
+ "description": "設定項目6"
49
+ }
50
+ ]
@@ -30,6 +30,21 @@ get "/config/*.*" do |file, ext|
30
30
  File.read "config/#{file}.#{ext}"
31
31
  end
32
32
 
33
+ post "/history/*.*" do |file, ext|
34
+ content_type "text/json", :charset => "utf-8"
35
+ puts "#{file}.#{ext}"
36
+ p = params[:param1]
37
+ buf = File.read "history/#{file}.#{ext}"
38
+ data = eval(buf)
39
+ if data != nil
40
+ if p != ""
41
+ JSON.generate data.find_all { |d| d =~ Regexp.new(p) }
42
+ else
43
+ JSON.generate data
44
+ end
45
+ end
46
+ end
47
+
33
48
  get "/open_dialog" do
34
49
  dialog_html = <<'EOS'
35
50
  <!DOCTYPE html>
@@ -74,6 +89,6 @@ configure do
74
89
 
75
90
  end
76
91
 
77
- #\ --port 53492
92
+ #\ --port 61047
78
93
 
79
94
  run Sinatra::Application
@@ -1,6 +1,6 @@
1
1
  body {
2
2
  color: #000000;
3
- background-color: #cac3ec4f;
3
+ background-color: #cac3ec4f;
4
4
  overflow: hidden;
5
5
  font-size: 12px;
6
6
  }
@@ -8,9 +8,12 @@ body {
8
8
  hr {
9
9
  color: #ffffff;
10
10
  background-color: #000000;
11
- height: 1px; /* 線の太さ */
12
- border: 1px; /* 枠の太さ */
13
- border-style: solid; /* 枠の種類 */
11
+ height: 1px;
12
+ /* 線の太さ */
13
+ border: 1px;
14
+ /* 枠の太さ */
15
+ border-style: solid;
16
+ /* 枠の種類 */
14
17
  }
15
18
 
16
19
  .error {
@@ -19,7 +22,7 @@ hr {
19
22
 
20
23
  .outarea {
21
24
  background-color: #FFFFFF;
22
- margin: 5px;
25
+ margin: 5px;
23
26
  padding: 5px;
24
27
  width: 95vw;
25
28
  height: 50vh;
@@ -28,15 +31,15 @@ hr {
28
31
 
29
32
  .inarea {
30
33
  border: thin solid #000000;
31
- margin: 5px;
34
+ margin: 5px;
32
35
  padding: 5px;
33
36
  width: 95%;
34
37
  }
35
38
 
36
39
  input.long {
37
40
  width: 90%;
38
- background-color: #FAFAFA;
39
- margin: 5px;
41
+ background-color: #FAFAFA;
42
+ margin: 5px;
40
43
  padding: 5px;
41
44
  }
42
45
 
@@ -64,11 +67,11 @@ textarea.long {
64
67
  }
65
68
 
66
69
  .ui-dialog {
67
- position: absolute;
68
- top: 0;
69
- left: 0;
70
- padding: .2em;
71
- outline: 0;
70
+ position: absolute;
71
+ top: 0;
72
+ left: 0;
73
+ padding: .2em;
74
+ outline: 0;
72
75
  }
73
76
 
74
77
  .long {
@@ -77,28 +80,36 @@ textarea.long {
77
80
 
78
81
  #setting_dialog {
79
82
  color: #796fe9;
80
- background-color: #000000;
83
+ background-color: #000000;
81
84
  }
82
85
 
83
86
  .setting_name {
84
87
  width: 200px;
85
88
  color: #796fe9;
86
- background-color: #000000;
89
+ background-color: #000000;
87
90
  }
88
91
 
89
92
  .setting_value {
90
93
  width: 300px;
91
94
  color: #796fe9;
92
- background-color: #000000;
95
+ background-color: #000000;
93
96
  }
94
97
 
95
98
  .setting_checkbox {
96
99
  color: #796fe9;
97
- background-color: #000000;
100
+ background-color: #000000;
98
101
  }
99
102
 
100
103
  ul.log {
101
- list-style-type: decimal;
104
+ list-style-type: decimal;
102
105
  font-size: 12px;
103
106
  color: #5d0a94;
107
+ }
108
+
109
+ input[type="search"] {
110
+ -webkit-appearance: searchfield;
111
+ }
112
+
113
+ input[type="search"]::-webkit-search-cancel-button {
114
+ -webkit-appearance: searchfield-cancel-button;
104
115
  }
File without changes
@@ -11,15 +11,15 @@
11
11
  <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
12
12
  <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
13
13
 
14
- <script src="http://localhost:53492/js/main.js"></script>
15
- <link rel="stylesheet" href="http://localhost:53492/css/index.css" type="text/css">
14
+ <script src="http://localhost:61047/js/main.js"></script>
15
+ <link rel="stylesheet" href="http://localhost:61047/css/index.css" type="text/css">
16
16
  </head>
17
17
 
18
18
  <body>
19
19
  <div id="msg_dialog" style="display:none;">
20
20
  <div id="msg_text">message</div>
21
21
  </div>
22
- <h4>GrepFind</h4>
22
+ <h4>RubyAppBase</h4>
23
23
  <hr>
24
24
  <table>
25
25
  <tr>
@@ -43,7 +43,7 @@
43
43
  </div>
44
44
  <table>
45
45
  <tr>
46
- <td class="long"><input class="inarea" type="text" id="upFile" name="upFile"></td>
46
+ <td class="long"><input class="inarea" type="search" id="upFile" name="upFile"></td>
47
47
  <td><input type="button" id="select_file" value="ファイル選択" /></td>
48
48
  </tr>
49
49
  </table>
@@ -53,7 +53,7 @@
53
53
  </div>
54
54
  <table>
55
55
  <tr>
56
- <td class="long"><input class="inarea" type="text" id="upDir" name="upDir"></td>
56
+ <td class="long"><input class="inarea" type="search" id="upDir" name="upDir"></td>
57
57
  <td><input type="button" id="select_dir" value="フォルダ選択" /></td>
58
58
  </tr>
59
59
  </table>
@@ -58,13 +58,15 @@ function server_connect(url) {
58
58
 
59
59
  if (evt.data.match(/^startup:/)) {
60
60
  file_name = evt.data.replace(/^startup:/, "");
61
- //alert(file_name);
62
61
  }
63
62
  else if (evt.data.match(/^app_end:normal/)) {
64
63
  open_dialog("終了しました");
65
64
  }
66
65
  else if (evt.data.match(/^app_end:error/)) {
67
66
  open_dialog("<font color='red'>エラーが発生しました</font>");
67
+ }
68
+ else if (evt.data.match(/^popup:/)) {
69
+ open_dialog(evt.data.replace(/^popup:/, ""));
68
70
  } else {
69
71
  var log = "<li>" + evt.data + "</li>";
70
72
  $('#log').append(log);
@@ -101,7 +103,7 @@ function autocomp(id, file_kind) {
101
103
  },
102
104
  source: function (req, resp) {
103
105
  $.ajax({
104
- url: "http://localhost:53492/search?path=" + $("#" + id).val() + "&kind=" + file_kind,
106
+ url: "http://localhost:61047/search?path=" + $("#" + id).val() + "&kind=" + file_kind,
105
107
  type: "GET",
106
108
  cache: false,
107
109
  dataType: "json",
@@ -123,6 +125,38 @@ function autocomp(id, file_kind) {
123
125
  });
124
126
  }
125
127
 
128
+ function autocomp_history(id, file_name) {
129
+ $("#" + id).autocomplete({
130
+ autoFocus: true,
131
+ minLength: 0,
132
+ delay: 0,
133
+ select: function (event, ui) {
134
+ jQuery("#" + id).val(ui.item.value);
135
+ $(this).keydown();
136
+ },
137
+ source: function (req, resp) {
138
+ $.ajax({
139
+ url: "http://localhost:61047/history/" + file_name,
140
+ type: "POST",
141
+ cache: false,
142
+ dataType: "json",
143
+ data: {
144
+ param1: req.term
145
+ },
146
+ success: function (o) {
147
+ resp(o);
148
+ },
149
+ error: function (xhr, ts, err) {
150
+ resp(['']);
151
+ }
152
+ });
153
+
154
+ }
155
+ }).focus(function () {
156
+ $(this).keydown();
157
+ });
158
+ }
159
+
126
160
  function select_file_dialog(search_id, file_kind, dialog_id, select_file, file_name) {
127
161
  $("#" + select_file).click(function () {
128
162
  autocomp(search_id, file_kind);
@@ -276,20 +310,25 @@ function openFile(file) {
276
310
 
277
311
  // 起動時の処理
278
312
  $(document).ready(function () {
279
- // サーバに接続
280
- server_connect("ws://localhost:53492/wsserver")
313
+
314
+ window.onload = function (e) {
315
+ console.log("onload");
316
+ // サーバに接続
317
+ server_connect("ws://localhost:61047/wsserver")
318
+ }
319
+
281
320
  // ウインドウサイズ
282
321
  var width = 800;
283
322
  var height = 600;
284
323
  $(window).resize(function () {
285
- $(".outarea").height($(window).height() - 300);
324
+ $(".outarea").height($(window).height() - 220);
286
325
  });
287
326
  // ウインドウの位置
288
327
  $(function () {
289
328
  window.resizeTo(width, height);
290
329
  window.moveTo((window.screen.width / 2) - (width / 2), (screen.height / 2) - (height / 2));
291
330
  //window.moveTo(0,0);
292
- $(".outarea").height($(window).height() - 300);
331
+ $(".outarea").height($(window).height() - 220);
293
332
  });
294
333
 
295
334
  $('.outarea').scroll(function () {
@@ -322,5 +361,7 @@ $(document).ready(function () {
322
361
 
323
362
  setting_dialog("setting", "setting_dialog", "config/setting.json");
324
363
 
364
+ autocomp_history("upFile", "history.json")
365
+
325
366
  });
326
367
 
@@ -10,8 +10,16 @@ class MyApp < AppMainBase
10
10
  argv.each do |v|
11
11
  yield v if block_given?
12
12
  end
13
+
14
+ # Browserにメッセージ送信
15
+ app_send("popup:start app #{argv[0]}")
16
+
17
+ # 履歴の保存
18
+ add_history("history.json", argv[0])
19
+
13
20
  while true
14
21
  yield Time.now.to_s if block_given?
22
+ puts Time.now.to_s
15
23
  yield @config["name1"]
16
24
  sleep 1
17
25
  break if @abort
@@ -5,6 +5,17 @@ class AppMainBase
5
5
  @aboet = false
6
6
  @exec = false
7
7
  @suspend = false
8
+ @ws = nil
9
+ end
10
+
11
+ def app_send(str)
12
+ if @ws != nil
13
+ @ws.send(str)
14
+ end
15
+ end
16
+
17
+ def set_ws(ws)
18
+ @ws = ws
8
19
  end
9
20
 
10
21
  def set_config(config)
@@ -27,6 +38,21 @@ class AppMainBase
27
38
  def resume()
28
39
  @suspend = false
29
40
  end
41
+
42
+ # 履歴の保存
43
+ def add_history(file, history_data)
44
+ buf = File.read "history/#{file}"
45
+ data = eval(buf)
46
+ if data == nil
47
+ data = []
48
+ end
49
+ if history_data.to_s != ""
50
+ data.prepend history_data
51
+ end
52
+ File.open("history/#{file}", "w") do |f|
53
+ f.write JSON.pretty_generate data.uniq
54
+ end
55
+ end
30
56
  end
31
57
 
32
58
  require "app_load.rb"
@@ -10,6 +10,35 @@ require "kconv"
10
10
  require "json"
11
11
  require "facter"
12
12
 
13
+ # ログ出力
14
+ module Output
15
+ def self.console_and_file(output_file)
16
+ defout = File.new(output_file, "a+")
17
+ class << defout
18
+ alias_method :write_org, :write
19
+
20
+ def puts(str)
21
+ STDOUT.write(str.to_s + "\n")
22
+ self.write_org(str.to_s + "\n")
23
+ self.flush
24
+ end
25
+
26
+ def write(str)
27
+ STDOUT.write(str)
28
+ self.write_org(str)
29
+ self.flush
30
+ end
31
+ end
32
+ $stdout = defout
33
+ end
34
+ end
35
+
36
+ Output.console_and_file("log.txt")
37
+
38
+ # ディレクトリ移動
39
+ dir = File.dirname(File.expand_path(__FILE__))
40
+ FileUtils.cd dir
41
+
13
42
  # 空きポートを取得
14
43
  def get_unused_port
15
44
  s = TCPServer.open(0)
@@ -37,22 +66,41 @@ buf = File.binread("index.html").toutf8
37
66
  buf.gsub!(/localhost:[0-9]+\//, "localhost:#{port}/")
38
67
  File.binwrite("index.html", buf)
39
68
 
40
- Thread.start {
41
- puts "start browser"
42
- json_file = File.dirname(File.expand_path(__FILE__)) + "/config/browser.json"
43
- json = JSON.parse(File.read json_file)
44
- puts json
45
- kernel = Facter.value(:kernel)
46
- if kernel == "windows"
47
- browser = json["chrome_win"]
48
- elsif kernel == "Linux"
49
- browser = json["chrome_linux"]
50
- else
51
- browser = json["chrome_win"]
52
- end
53
- browser += " -app=http://localhost:#{port}"
54
- puts browser
55
- system browser
56
- }
69
+ begin
70
+ Thread.start {
71
+ puts "wait start web server"
72
+ while true
73
+ begin
74
+ s = TCPSocket.open("localhost", port)
75
+ s.close
76
+ break
77
+ rescue
78
+ puts $!
79
+ sleep 0.1
80
+ end
81
+ end
57
82
 
58
- Rack::Server.start
83
+ puts "start browser"
84
+ json_file = File.dirname(File.expand_path(__FILE__)) + "/config/browser.json"
85
+ json = JSON.parse(File.read json_file)
86
+ puts json
87
+ kernel = Facter.value(:kernel)
88
+ if kernel == "windows"
89
+ browser = json["chrome_win"]
90
+ elsif kernel == "Linux"
91
+ browser = json["chrome_linux"]
92
+ else
93
+ browser = json["chrome_win"]
94
+ end
95
+ browser += " -app=http://localhost:#{port}"
96
+ puts browser
97
+ system browser
98
+ }
99
+
100
+ # start web server
101
+ Rack::Server.start
102
+ rescue
103
+ puts $!
104
+ puts $@
105
+ exit
106
+ end
@@ -1,6 +1,7 @@
1
1
  require "./server_app_base"
2
2
  require "json"
3
3
  require "cgi"
4
+ require "thread"
4
5
 
5
6
  def config_json_hash(json)
6
7
  config = {}
@@ -10,8 +11,23 @@ def config_json_hash(json)
10
11
  return config
11
12
  end
12
13
 
14
+ $ws_exit_thread = nil
15
+
13
16
  class WsServer < Sinatra::Base
14
- $ws_list = []
17
+ def initialize
18
+ super
19
+ @ws_list = []
20
+ @ws_lock = Mutex.new
21
+ end
22
+
23
+ def ws_send(str)
24
+ @ws_lock.synchronize do
25
+ if @ws_list[0] != nil
26
+ @ws_list[0].send(str)
27
+ end
28
+ end
29
+ end
30
+
15
31
  json_config = nil
16
32
  exec_thread = nil
17
33
  get "" do
@@ -20,8 +36,18 @@ class WsServer < Sinatra::Base
20
36
  else
21
37
  request.websocket do |ws|
22
38
  ws.onopen do
23
- ws.send("startup:#{$startup_file}")
24
- $ws_list << ws
39
+ puts "ws.open"
40
+ @ws_lock.synchronize do
41
+ @ws_list << ws
42
+ $app.set_ws(ws)
43
+ pp "ws=#{ws}"
44
+ end
45
+ ws_send("startup:#{$startup_file}")
46
+ puts "ws_exit_thread=#{$ws_exit_thread}"
47
+ if $ws_exit_thread != nil
48
+ puts "ws_exit_thread kill"
49
+ Thread.kill $ws_exit_thread
50
+ end
25
51
  end
26
52
  ws.onmessage do |msg|
27
53
  puts msg
@@ -34,14 +60,14 @@ class WsServer < Sinatra::Base
34
60
  exec_thread = Thread.new {
35
61
  begin
36
62
  $app.start(argv.split(",")) do |out|
37
- ws.send(out)
63
+ ws_send(out)
38
64
  end
39
- ws.send("app_end:normal")
65
+ ws_send("app_end:normal")
40
66
  rescue
41
67
  puts $!
42
68
  puts $@
43
69
  puts "app_end:err"
44
- ws.send("app_end:error")
70
+ ws_send("app_end:error")
45
71
  ensure
46
72
  puts "exit thread"
47
73
  exec_thread = nil
@@ -49,7 +75,7 @@ class WsServer < Sinatra::Base
49
75
  }
50
76
  else
51
77
  puts "app_end:err"
52
- ws.send("app_end:error")
78
+ ws_send("app_end:error")
53
79
  end
54
80
  end
55
81
  if msg =~ /^stop/
@@ -83,23 +109,27 @@ class WsServer < Sinatra::Base
83
109
  }
84
110
  end
85
111
 
112
+ # アプリケーション終了
86
113
  if msg == "exit"
87
- unless ENV["OCRA"] == "true"
88
- halt
89
- #exit
90
- end
114
+ #halt
115
+ exit
91
116
  end
92
117
  end
118
+
119
+ # close websocket
93
120
  ws.onclose do
94
121
  puts "websocket closed"
95
- $ws_list.delete(ws)
96
- puts $ws_list.size
97
- if $ws_list.size == 0
98
- puts ENV["OCRA"]
99
- unless ENV["OCRA"] == "true"
122
+ @ws_lock.synchronize do
123
+ @ws_list.delete(ws)
124
+ end
125
+ puts @ws_list.size
126
+ if @ws_list.size == 0
127
+ $ws_exit_thread = Thread.start {
128
+ sleep 1
100
129
  #halt
101
130
  exit
102
- end
131
+ }
132
+ puts "ws_exit_thread=#{$ws_exit_thread}"
103
133
  end
104
134
  end
105
135
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: browser_app_base
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - masataka kuwayama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-21 00:00:00.000000000 Z
11
+ date: 2021-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -118,6 +118,7 @@ files:
118
118
  - lib/template/config/browser.json
119
119
  - lib/template/config/setting.json
120
120
  - lib/template/css/index.css
121
+ - lib/template/history/history.json
121
122
  - lib/template/index.html
122
123
  - lib/template/js/main.js
123
124
  - lib/template/my_app_sample.rb