narou 2.8.3.1 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of narou might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/ChangeLog.md +77 -0
- data/Gemfile +2 -1
- data/README.md +69 -86
- data/lib/command/convert.rb +10 -11
- data/lib/command/init.rb +2 -2
- data/lib/command/list.rb +12 -3
- data/lib/command/setting.rb +20 -5
- data/lib/command/update.rb +0 -3
- data/lib/command/version.rb +2 -3
- data/lib/command/web.rb +58 -7
- data/lib/converterbase.rb +7 -24
- data/lib/database.rb +7 -6
- data/lib/device.rb +15 -1
- data/lib/device/ibunko.rb +1 -2
- data/lib/device/library/mac.rb +7 -0
- data/lib/downloader.rb +44 -21
- data/lib/extension.rb +25 -0
- data/lib/helper.rb +4 -3
- data/lib/html.rb +18 -2
- data/lib/narou.rb +20 -0
- data/lib/novelconverter.rb +11 -35
- data/lib/novelinfo.rb +19 -8
- data/lib/novelsetting.rb +0 -6
- data/lib/version.rb +1 -1
- data/lib/web/appserver.rb +134 -15
- data/lib/web/public/favicon.ico +0 -0
- data/lib/web/public/resources/common.ui.js +2 -2
- data/lib/web/public/resources/narou.library.js +657 -91
- data/lib/web/public/resources/narou.queue.js +1 -1
- data/lib/web/public/resources/narou.ui.js +253 -102
- data/lib/web/public/resources/sprintf.js +245 -0
- data/lib/web/pushserver.rb +14 -3
- data/lib/web/views/_about.haml +188 -0
- data/lib/web/views/{diff_list.haml → _diff_list.haml} +0 -0
- data/lib/web/views/{edit_replace_txt.haml → _edit_replace_txt.haml} +4 -4
- data/lib/web/views/_rebooting.haml +18 -0
- data/lib/web/views/bookmarklet/download.js.erb +2 -2
- data/lib/web/views/bookmarklet/insert_button.js.erb +1 -1
- data/lib/web/views/edit_menu.haml +223 -0
- data/lib/web/views/help.haml +29 -12
- data/lib/web/views/index.haml +99 -88
- data/lib/web/views/layout.haml +5 -3
- data/lib/web/views/notepad.haml +39 -0
- data/lib/web/views/novels/setting.haml +15 -5
- data/lib/web/views/settings.haml +2 -2
- data/lib/web/views/style.scss +72 -21
- data/lib/web/views/widget/download.haml +3 -2
- data/lib/web/views/widget/drag_and_drop.haml +3 -2
- data/lib/web/views/widget/notepad.haml +44 -0
- data/narou.gemspec +75 -6
- data/narou.rb +8 -14
- data/preset/ncode.syosetu.com/n5115cq/converter.rb +30 -0
- data/preset/ncode.syosetu.com/n7594ct/converter.rb +37 -0
- data/preset/ncode.syosetu.com/n8725k/converter.rb +1 -1
- data/preset/vertical_font.css +0 -10
- data/spec/generator/convert_spec_gen.rb +2 -0
- data/template/novel.txt.erb +3 -0
- data/webnovel/https.syosetu.org.yaml +1 -1
- data/webnovel/kakuyomu.jp.yaml +82 -0
- data/webnovel/ncode.syosetu.com.yaml +1 -0
- data/webnovel/syosetu.org.yaml +1 -1
- metadata +89 -12
- data/lib/web/views/about.haml +0 -85
- data/preset/DMincho.ttf +0 -0
@@ -0,0 +1,245 @@
|
|
1
|
+
/* globals window, exports, define */
|
2
|
+
|
3
|
+
(function(window) {
|
4
|
+
'use strict'
|
5
|
+
|
6
|
+
var re = {
|
7
|
+
not_string: /[^s]/,
|
8
|
+
not_bool: /[^t]/,
|
9
|
+
not_type: /[^T]/,
|
10
|
+
not_primitive: /[^v]/,
|
11
|
+
number: /[diefg]/,
|
12
|
+
numeric_arg: /bcdiefguxX/,
|
13
|
+
json: /[j]/,
|
14
|
+
not_json: /[^j]/,
|
15
|
+
text: /^[^\x25]+/,
|
16
|
+
modulo: /^\x25{2}/,
|
17
|
+
placeholder: /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-gijostTuvxX])/,
|
18
|
+
key: /^([a-z_][a-z_\d]*)/i,
|
19
|
+
key_access: /^\.([a-z_][a-z_\d]*)/i,
|
20
|
+
index_access: /^\[(\d+)\]/,
|
21
|
+
sign: /^[\+\-]/
|
22
|
+
}
|
23
|
+
|
24
|
+
function sprintf() {
|
25
|
+
var key = arguments[0], cache = sprintf.cache
|
26
|
+
if (!(cache[key] && cache.hasOwnProperty(key))) {
|
27
|
+
cache[key] = sprintf.parse(key)
|
28
|
+
}
|
29
|
+
return sprintf.format.call(null, cache[key], arguments)
|
30
|
+
}
|
31
|
+
|
32
|
+
sprintf.format = function(parse_tree, argv) {
|
33
|
+
var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length, is_positive = true, sign = ''
|
34
|
+
for (i = 0; i < tree_length; i++) {
|
35
|
+
node_type = get_type(parse_tree[i])
|
36
|
+
if (node_type === 'string') {
|
37
|
+
output[output.length] = parse_tree[i]
|
38
|
+
}
|
39
|
+
else if (node_type === 'array') {
|
40
|
+
match = parse_tree[i] // convenience purposes only
|
41
|
+
if (match[2]) { // keyword argument
|
42
|
+
arg = argv[cursor]
|
43
|
+
for (k = 0; k < match[2].length; k++) {
|
44
|
+
if (!arg.hasOwnProperty(match[2][k])) {
|
45
|
+
throw new Error(sprintf('[sprintf] property "%s" does not exist', match[2][k]))
|
46
|
+
}
|
47
|
+
arg = arg[match[2][k]]
|
48
|
+
}
|
49
|
+
}
|
50
|
+
else if (match[1]) { // positional argument (explicit)
|
51
|
+
arg = argv[match[1]]
|
52
|
+
}
|
53
|
+
else { // positional argument (implicit)
|
54
|
+
arg = argv[cursor++]
|
55
|
+
}
|
56
|
+
|
57
|
+
if (re.not_type.test(match[8]) && re.not_primitive.test(match[8]) && get_type(arg) == 'function') {
|
58
|
+
arg = arg()
|
59
|
+
}
|
60
|
+
|
61
|
+
if (re.numeric_arg.test(match[8]) && (get_type(arg) != 'number' && isNaN(arg))) {
|
62
|
+
throw new TypeError(sprintf("[sprintf] expecting number but found %s", get_type(arg)))
|
63
|
+
}
|
64
|
+
|
65
|
+
if (re.number.test(match[8])) {
|
66
|
+
is_positive = arg >= 0
|
67
|
+
}
|
68
|
+
|
69
|
+
switch (match[8]) {
|
70
|
+
case 'b':
|
71
|
+
arg = parseInt(arg, 10).toString(2)
|
72
|
+
break
|
73
|
+
case 'c':
|
74
|
+
arg = String.fromCharCode(parseInt(arg, 10))
|
75
|
+
break
|
76
|
+
case 'd':
|
77
|
+
case 'i':
|
78
|
+
arg = parseInt(arg, 10)
|
79
|
+
break
|
80
|
+
case 'j':
|
81
|
+
arg = JSON.stringify(arg, null, match[6] ? parseInt(match[6]) : 0)
|
82
|
+
break
|
83
|
+
case 'e':
|
84
|
+
arg = match[7] ? parseFloat(arg).toExponential(match[7]) : parseFloat(arg).toExponential()
|
85
|
+
break
|
86
|
+
case 'f':
|
87
|
+
arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg)
|
88
|
+
break
|
89
|
+
case 'g':
|
90
|
+
arg = match[7] ? parseFloat(arg).toPrecision(match[7]) : parseFloat(arg)
|
91
|
+
break
|
92
|
+
case 'o':
|
93
|
+
arg = arg.toString(8)
|
94
|
+
break
|
95
|
+
case 's':
|
96
|
+
arg = String(arg)
|
97
|
+
arg = (match[7] ? arg.substring(0, match[7]) : arg)
|
98
|
+
break
|
99
|
+
case 't':
|
100
|
+
arg = String(!!arg)
|
101
|
+
arg = (match[7] ? arg.substring(0, match[7]) : arg)
|
102
|
+
break
|
103
|
+
case 'T':
|
104
|
+
arg = get_type(arg)
|
105
|
+
arg = (match[7] ? arg.substring(0, match[7]) : arg)
|
106
|
+
break
|
107
|
+
case 'u':
|
108
|
+
arg = parseInt(arg, 10) >>> 0
|
109
|
+
break
|
110
|
+
case 'v':
|
111
|
+
arg = arg.valueOf()
|
112
|
+
arg = (match[7] ? arg.substring(0, match[7]) : arg)
|
113
|
+
break
|
114
|
+
case 'x':
|
115
|
+
arg = parseInt(arg, 10).toString(16)
|
116
|
+
break
|
117
|
+
case 'X':
|
118
|
+
arg = parseInt(arg, 10).toString(16).toUpperCase()
|
119
|
+
break
|
120
|
+
}
|
121
|
+
if (re.json.test(match[8])) {
|
122
|
+
output[output.length] = arg
|
123
|
+
}
|
124
|
+
else {
|
125
|
+
if (re.number.test(match[8]) && (!is_positive || match[3])) {
|
126
|
+
sign = is_positive ? '+' : '-'
|
127
|
+
arg = arg.toString().replace(re.sign, '')
|
128
|
+
}
|
129
|
+
else {
|
130
|
+
sign = ''
|
131
|
+
}
|
132
|
+
pad_character = match[4] ? match[4] === '0' ? '0' : match[4].charAt(1) : ' '
|
133
|
+
pad_length = match[6] - (sign + arg).length
|
134
|
+
pad = match[6] ? (pad_length > 0 ? str_repeat(pad_character, pad_length) : '') : ''
|
135
|
+
output[output.length] = match[5] ? sign + arg + pad : (pad_character === '0' ? sign + pad + arg : pad + sign + arg)
|
136
|
+
}
|
137
|
+
}
|
138
|
+
}
|
139
|
+
return output.join('')
|
140
|
+
}
|
141
|
+
|
142
|
+
sprintf.cache = {}
|
143
|
+
|
144
|
+
sprintf.parse = function(fmt) {
|
145
|
+
var _fmt = fmt, match = [], parse_tree = [], arg_names = 0
|
146
|
+
while (_fmt) {
|
147
|
+
if ((match = re.text.exec(_fmt)) !== null) {
|
148
|
+
parse_tree[parse_tree.length] = match[0]
|
149
|
+
}
|
150
|
+
else if ((match = re.modulo.exec(_fmt)) !== null) {
|
151
|
+
parse_tree[parse_tree.length] = '%'
|
152
|
+
}
|
153
|
+
else if ((match = re.placeholder.exec(_fmt)) !== null) {
|
154
|
+
if (match[2]) {
|
155
|
+
arg_names |= 1
|
156
|
+
var field_list = [], replacement_field = match[2], field_match = []
|
157
|
+
if ((field_match = re.key.exec(replacement_field)) !== null) {
|
158
|
+
field_list[field_list.length] = field_match[1]
|
159
|
+
while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
|
160
|
+
if ((field_match = re.key_access.exec(replacement_field)) !== null) {
|
161
|
+
field_list[field_list.length] = field_match[1]
|
162
|
+
}
|
163
|
+
else if ((field_match = re.index_access.exec(replacement_field)) !== null) {
|
164
|
+
field_list[field_list.length] = field_match[1]
|
165
|
+
}
|
166
|
+
else {
|
167
|
+
throw new SyntaxError("[sprintf] failed to parse named argument key")
|
168
|
+
}
|
169
|
+
}
|
170
|
+
}
|
171
|
+
else {
|
172
|
+
throw new SyntaxError("[sprintf] failed to parse named argument key")
|
173
|
+
}
|
174
|
+
match[2] = field_list
|
175
|
+
}
|
176
|
+
else {
|
177
|
+
arg_names |= 2
|
178
|
+
}
|
179
|
+
if (arg_names === 3) {
|
180
|
+
throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported")
|
181
|
+
}
|
182
|
+
parse_tree[parse_tree.length] = match
|
183
|
+
}
|
184
|
+
else {
|
185
|
+
throw new SyntaxError("[sprintf] unexpected placeholder")
|
186
|
+
}
|
187
|
+
_fmt = _fmt.substring(match[0].length)
|
188
|
+
}
|
189
|
+
return parse_tree
|
190
|
+
}
|
191
|
+
|
192
|
+
var vsprintf = function(fmt, argv, _argv) {
|
193
|
+
_argv = (argv || []).slice(0)
|
194
|
+
_argv.splice(0, 0, fmt)
|
195
|
+
return sprintf.apply(null, _argv)
|
196
|
+
}
|
197
|
+
|
198
|
+
/**
|
199
|
+
* helpers
|
200
|
+
*/
|
201
|
+
function get_type(variable) {
|
202
|
+
if (typeof variable === 'number') {
|
203
|
+
return 'number'
|
204
|
+
}
|
205
|
+
else if (typeof variable === 'string') {
|
206
|
+
return 'string'
|
207
|
+
}
|
208
|
+
else {
|
209
|
+
return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase()
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
var preformattedPadding = {
|
214
|
+
'0': ['', '0', '00', '000', '0000', '00000', '000000', '0000000'],
|
215
|
+
' ': ['', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
|
216
|
+
'_': ['', '_', '__', '___', '____', '_____', '______', '_______'],
|
217
|
+
}
|
218
|
+
function str_repeat(input, multiplier) {
|
219
|
+
if (multiplier >= 0 && multiplier <= 7 && preformattedPadding[input]) {
|
220
|
+
return preformattedPadding[input][multiplier]
|
221
|
+
}
|
222
|
+
return Array(multiplier + 1).join(input)
|
223
|
+
}
|
224
|
+
|
225
|
+
/**
|
226
|
+
* export to either browser or node.js
|
227
|
+
*/
|
228
|
+
if (typeof exports !== 'undefined') {
|
229
|
+
exports.sprintf = sprintf
|
230
|
+
exports.vsprintf = vsprintf
|
231
|
+
}
|
232
|
+
else {
|
233
|
+
window.sprintf = sprintf
|
234
|
+
window.vsprintf = vsprintf
|
235
|
+
|
236
|
+
if (typeof define === 'function' && define.amd) {
|
237
|
+
define(function() {
|
238
|
+
return {
|
239
|
+
sprintf: sprintf,
|
240
|
+
vsprintf: vsprintf
|
241
|
+
}
|
242
|
+
})
|
243
|
+
}
|
244
|
+
}
|
245
|
+
})(typeof window === 'undefined' ? this : window);
|
data/lib/web/pushserver.rb
CHANGED
@@ -19,7 +19,7 @@ module Narou
|
|
19
19
|
attr_reader :accepted_domains, :connections
|
20
20
|
|
21
21
|
def accepted_domains=(domains)
|
22
|
-
@accepted_domains = domains
|
22
|
+
@accepted_domains = Array(domains)
|
23
23
|
end
|
24
24
|
|
25
25
|
def initialize
|
@@ -100,12 +100,23 @@ module Narou
|
|
100
100
|
# echo 以外のイベントは履歴に保存しない
|
101
101
|
message = data[:echo]
|
102
102
|
if message
|
103
|
-
|
104
|
-
@history.shift
|
103
|
+
stack_to_history(message)
|
105
104
|
end
|
106
105
|
rescue JSON::GeneratorError => e
|
107
106
|
STDERR.puts $@.shift + ": #{e.message} (#{e.class})"
|
108
107
|
end
|
108
|
+
|
109
|
+
def stack_to_history(message)
|
110
|
+
if message == "." && @history[-1] =~ /\A\.+\z/
|
111
|
+
# 進行中を表す .... の出力でヒストリーが消費されるのを防ぐため、
|
112
|
+
# 連続した . は一つにまとめる
|
113
|
+
@history[-1] << "."
|
114
|
+
else
|
115
|
+
@history.push(message)
|
116
|
+
@history.shift
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
109
120
|
end
|
110
121
|
end
|
111
122
|
|
@@ -0,0 +1,188 @@
|
|
1
|
+
:javascript
|
2
|
+
+function() {
|
3
|
+
var action = new Narou.Action;
|
4
|
+
|
5
|
+
function getCurrentVersion() {
|
6
|
+
var dfd = jQuery.Deferred();
|
7
|
+
$.ajax({
|
8
|
+
type: "GET",
|
9
|
+
url: "/api/version/current.json",
|
10
|
+
dataType: "json",
|
11
|
+
success: function(json) {
|
12
|
+
$("#current-version").text(json.version);
|
13
|
+
dfd.resolve(json.version);
|
14
|
+
},
|
15
|
+
error: function() {
|
16
|
+
dfd.reject();
|
17
|
+
}
|
18
|
+
});
|
19
|
+
return dfd;
|
20
|
+
}
|
21
|
+
|
22
|
+
function getLatestVersion() {
|
23
|
+
var dfd = jQuery.Deferred();
|
24
|
+
$.ajax({
|
25
|
+
type: "GET",
|
26
|
+
url: "/api/version/latest.json",
|
27
|
+
dataType: "json",
|
28
|
+
success: function(json) {
|
29
|
+
$("#latest-version").text(json.version);
|
30
|
+
dfd.resolve(json.version);
|
31
|
+
},
|
32
|
+
error: function() {
|
33
|
+
dfd.reject();
|
34
|
+
}
|
35
|
+
});
|
36
|
+
return dfd;
|
37
|
+
}
|
38
|
+
|
39
|
+
function updateButtonHandler() {
|
40
|
+
var dfd = jQuery.Deferred();
|
41
|
+
$("#version-update-button").one("click", function(e) {
|
42
|
+
e.preventDefault();
|
43
|
+
$(this).hide();
|
44
|
+
$("#fail-update-system").hide();
|
45
|
+
dfd.resolve();
|
46
|
+
});
|
47
|
+
return dfd;
|
48
|
+
}
|
49
|
+
|
50
|
+
function callUpdateSystem() {
|
51
|
+
var dfd = jQuery.Deferred();
|
52
|
+
$("#version-updating").show();
|
53
|
+
$("#gem-result-log").hide();
|
54
|
+
action.updateSystem(function(result, log) {
|
55
|
+
$("#version-updating").hide();
|
56
|
+
$("#gem-result-log").text(log);
|
57
|
+
if (result == "success")
|
58
|
+
dfd.resolve();
|
59
|
+
else
|
60
|
+
dfd.reject(result);
|
61
|
+
});
|
62
|
+
return dfd;
|
63
|
+
}
|
64
|
+
|
65
|
+
function rebootButtonHandler() {
|
66
|
+
$("#gem-result-log").addClass("large").show();
|
67
|
+
$("#reboot-button")
|
68
|
+
.show()
|
69
|
+
.on("click", function(e) {
|
70
|
+
action.rebootDialog();
|
71
|
+
});
|
72
|
+
}
|
73
|
+
|
74
|
+
function failUpdateSystem(result) {
|
75
|
+
if (result == "failure") {
|
76
|
+
$("#fail-update-system").show();
|
77
|
+
$("#gem-result-log").show();
|
78
|
+
updateSysmteProcess();
|
79
|
+
}
|
80
|
+
else if (result == "nothing") {
|
81
|
+
$("#nothing-to-update").show();
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
function updateSysmteProcess() {
|
86
|
+
$("#version-update-button").show();
|
87
|
+
updateButtonHandler()
|
88
|
+
.then(callUpdateSystem)
|
89
|
+
.then(rebootButtonHandler)
|
90
|
+
.fail(failUpdateSystem);
|
91
|
+
}
|
92
|
+
|
93
|
+
$result = $("#result-of-version-checking");
|
94
|
+
$result.children("div").hide();
|
95
|
+
|
96
|
+
$("#version-update-button").hide();
|
97
|
+
$("#reboot-button").hide();
|
98
|
+
$("#version-updating").hide();
|
99
|
+
$("#fail-update-system").hide();
|
100
|
+
$("#nothing-to-update").hide();
|
101
|
+
$("#gem-result-log").hide();
|
102
|
+
|
103
|
+
action.checkUpdatedSystem({
|
104
|
+
// まだgemのアップデートは行われていないので、バージョンチェックからはじめる
|
105
|
+
not_updated: function() {
|
106
|
+
$result.children(".checking").show();
|
107
|
+
|
108
|
+
$.when(
|
109
|
+
getCurrentVersion(),
|
110
|
+
getLatestVersion()
|
111
|
+
)
|
112
|
+
.done(function(current_version, latest_version) {
|
113
|
+
$result.children(".checking").hide();
|
114
|
+
if (latest_version > current_version) {
|
115
|
+
$("#latest-version").text(latest_version);
|
116
|
+
$result.children(".need-an-update").show();
|
117
|
+
}
|
118
|
+
else {
|
119
|
+
$result.children(".version-is-latest").show();
|
120
|
+
}
|
121
|
+
})
|
122
|
+
.fail(function() {
|
123
|
+
$result.children(".checking").hide();
|
124
|
+
$result.children(".error").show();
|
125
|
+
});
|
126
|
+
|
127
|
+
updateSysmteProcess();
|
128
|
+
},
|
129
|
+
|
130
|
+
// すでにgemをアップデート済みなので、再起動ボタンを最初から表示する
|
131
|
+
already_updated: function(log) {
|
132
|
+
$result.children(".need-an-update").show();
|
133
|
+
$("#latest-version-found").hide();
|
134
|
+
$("#reboot-button").show();
|
135
|
+
$("#gem-result-log").text(log);
|
136
|
+
rebootButtonHandler();
|
137
|
+
}
|
138
|
+
});
|
139
|
+
|
140
|
+
}();
|
141
|
+
|
142
|
+
%div.link-to-changelog-in-about
|
143
|
+
%a.btn.btn-default.btn-sm(href="https://github.com/whiteleaf7/narou/blob/master/ChangeLog.md" target="_blank")
|
144
|
+
更新履歴
|
145
|
+
%span.glyphicon.glyphicon-new-window
|
146
|
+
|
147
|
+
%div(style="text-align:center")
|
148
|
+
%h1
|
149
|
+
%strong Narou.rb
|
150
|
+
%div
|
151
|
+
Version #{@narourb_version}
|
152
|
+
%div
|
153
|
+
Copyright 2013 whiteleaf. All rights reserved.
|
154
|
+
#result-of-version-checking(style="margin-top:10px")
|
155
|
+
.checking
|
156
|
+
%span.rotate-progress
|
157
|
+
%span.icon
|
158
|
+
%span.text アップデートを確認しています...
|
159
|
+
.version-is-latest
|
160
|
+
%p
|
161
|
+
%span.glyphicon.glyphicon-thumbs-up.text-primary
|
162
|
+
Narou.rb は最新版です。
|
163
|
+
.need-an-update
|
164
|
+
%p
|
165
|
+
%span#latest-version-found
|
166
|
+
%span.glyphicon.glyphicon-exclamation-sign.text-primary
|
167
|
+
新しいバージョン(<span id="latest-version"></span>)が見つかりました。<br>
|
168
|
+
%a#version-update-button.btn.btn-primary.btn-sm
|
169
|
+
%b Narou.rb を更新する
|
170
|
+
%span#version-updating
|
171
|
+
%span.rotate-progress
|
172
|
+
%span.icon
|
173
|
+
%span.text 更新しています。
|
174
|
+
%a#reboot-button.btn.btn-success.btn-sm
|
175
|
+
%b 再起動して更新を反映する
|
176
|
+
%span#nothing-to-update.text-success
|
177
|
+
Narou.rb はすでに最新版です。
|
178
|
+
%p#fail-update-system.text-danger
|
179
|
+
Narou.rb の更新に失敗しました。
|
180
|
+
.error
|
181
|
+
%span.text-danger
|
182
|
+
最新バージョンの取得に失敗しました。
|
183
|
+
|
184
|
+
%pre#gem-result-log.log-box
|
185
|
+
|
186
|
+
.well.well-sm(style="font-size:80%; margin-top: 10px")
|
187
|
+
#{@ruby_version}<br>
|
188
|
+
#{env["HTTP_USER_AGENT"]}
|