rroonga 1.1.0 → 1.2.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/NEWS.ja.rdoc +18 -0
- data/NEWS.rdoc +18 -0
- data/bin/grndump +71 -0
- data/ext/groonga/rb-grn-accessor.c +64 -1
- data/ext/groonga/rb-grn-context.c +40 -1
- data/ext/groonga/rb-grn-database.c +47 -5
- data/ext/groonga/rb-grn-index-column.c +77 -7
- data/ext/groonga/rb-grn-object.c +8 -4
- data/ext/groonga/rb-grn-table-cursor.c +56 -1
- data/ext/groonga/rb-grn-table-key-support.c +2 -2
- data/ext/groonga/rb-grn-table.c +10 -38
- data/ext/groonga/rb-grn.h +11 -1
- data/html/index.html +6 -6
- data/html/ranguba.css +8 -1
- data/lib/groonga.rb +1 -0
- data/lib/groonga/dumper.rb +481 -0
- data/lib/groonga/schema.rb +54 -181
- data/rroonga-build.rb +1 -1
- data/test-unit-notify/Rakefile +47 -0
- data/test-unit-notify/lib/test/unit/notify.rb +104 -0
- data/test-unit/COPYING +56 -0
- data/test-unit/GPL +340 -0
- data/test-unit/PSFL +271 -0
- data/test-unit/Rakefile +18 -5
- data/test-unit/html/bar.svg +153 -0
- data/test-unit/html/developer.svg +469 -0
- data/test-unit/html/favicon.ico +0 -0
- data/test-unit/html/favicon.svg +82 -0
- data/test-unit/html/heading-mark.svg +393 -0
- data/test-unit/html/index.html +235 -13
- data/test-unit/html/index.html.ja +258 -15
- data/test-unit/html/install.svg +636 -0
- data/test-unit/html/logo.svg +483 -0
- data/test-unit/html/test-unit.css +339 -0
- data/test-unit/html/tutorial.svg +559 -0
- data/test-unit/lib/test/unit.rb +6 -1
- data/test-unit/lib/test/unit/assertions.rb +115 -11
- data/test-unit/lib/test/unit/autorunner.rb +5 -2
- data/test-unit/lib/test/unit/collector/load.rb +1 -1
- data/test-unit/lib/test/unit/color-scheme.rb +6 -2
- data/test-unit/lib/test/unit/diff.rb +17 -1
- data/test-unit/lib/test/unit/testcase.rb +7 -0
- data/test-unit/lib/test/unit/testresult.rb +34 -2
- data/test-unit/lib/test/unit/ui/console/testrunner.rb +9 -45
- data/test-unit/lib/test/unit/ui/tap/testrunner.rb +2 -12
- data/test-unit/lib/test/unit/ui/testrunner.rb +25 -0
- data/test-unit/lib/test/unit/util/backtracefilter.rb +1 -0
- data/test-unit/lib/test/unit/util/output.rb +31 -0
- data/test-unit/lib/test/unit/version.rb +1 -1
- data/test-unit/test/test-color-scheme.rb +4 -2
- data/test-unit/test/test_assertions.rb +51 -5
- data/test-unit/test/ui/test_tap.rb +33 -0
- data/test-unit/test/util/test-output.rb +11 -0
- data/test/groonga-test-utils.rb +1 -0
- data/test/test-accessor.rb +32 -0
- data/test/test-context.rb +7 -1
- data/test/test-database-dumper.rb +156 -0
- data/test/test-index-column.rb +67 -1
- data/test/test-schema-dumper.rb +181 -0
- data/test/test-schema.rb +53 -97
- data/test/test-table-dumper.rb +83 -0
- metadata +48 -11
- data/ext/groonga/mkmf.log +0 -99
- data/test-unit/html/classic.html +0 -15
data/lib/groonga/schema.rb
CHANGED
@@ -386,9 +386,11 @@ module Groonga
|
|
386
386
|
end
|
387
387
|
end
|
388
388
|
|
389
|
-
#
|
390
|
-
#
|
391
|
-
#
|
389
|
+
# スキーマの内容を文字列をRubyスクリプト形式またはgrn式
|
390
|
+
# 形式で返す。デフォルトはRubyスクリプト形式である。
|
391
|
+
# Rubyスクリプト形式で返された値は
|
392
|
+
# Groonga::Schema.restoreすることによりスキーマ内に組み
|
393
|
+
# 込むことができる。
|
392
394
|
#
|
393
395
|
# dump.rb:
|
394
396
|
# File.open("/tmp/groonga-schema.rb", "w") do |schema|
|
@@ -400,14 +402,36 @@ module Groonga
|
|
400
402
|
# Groonga::Database.create(:path => "/tmp/new-db.grn")
|
401
403
|
# Groonga::Schema.restore(dumped_text)
|
402
404
|
#
|
405
|
+
# grn式形式で返された値はgroongaコマンドで読み込むこと
|
406
|
+
# ができる。
|
407
|
+
#
|
408
|
+
# dump.rb:
|
409
|
+
# File.open("/tmp/groonga-schema.grn", "w") do |schema|
|
410
|
+
# dumped_text = Groonga::Schema.dump(:syntax => :command)
|
411
|
+
# end
|
412
|
+
#
|
413
|
+
# % groonga db/path < /tmp/groonga-schema.grn
|
414
|
+
#
|
403
415
|
# _options_に指定可能な値は以下の通り。
|
404
416
|
#
|
405
417
|
# [+:context+]
|
406
418
|
# スキーマ定義時に使用するGroonga::Contextを指定する。
|
407
419
|
# 省略した場合はGroonga::Context.defaultを使用する。
|
420
|
+
#
|
421
|
+
# [+:syntax+]
|
422
|
+
# スキーマの文字列の形式を指定する。指定可能な値は以
|
423
|
+
# 下の通り。
|
424
|
+
#
|
425
|
+
# [+:ruby+]
|
426
|
+
# Rubyスクリプト形式。省略した場合、+nil+の場合も
|
427
|
+
# Rubyスクリプト形式になる。
|
428
|
+
#
|
429
|
+
# [+:command+]
|
430
|
+
# groongaコマンド形式。groongaコマンドで読み込むこ
|
431
|
+
# とができる。
|
408
432
|
def dump(options={})
|
409
|
-
|
410
|
-
|
433
|
+
schema = new(:context => options[:context],
|
434
|
+
:syntax => options[:syntax])
|
411
435
|
schema.dump
|
412
436
|
end
|
413
437
|
|
@@ -473,10 +497,11 @@ module Groonga
|
|
473
497
|
"mecab" => "TokenMecab",
|
474
498
|
"token_mecab"=> "TokenMecab",
|
475
499
|
}
|
476
|
-
def normalize_type(type) # :nodoc:
|
500
|
+
def normalize_type(type, options={}) # :nodoc:
|
477
501
|
return type if type.nil?
|
478
502
|
return type if type.is_a?(Groonga::Object)
|
479
503
|
type = type.to_s if type.is_a?(Symbol)
|
504
|
+
return type if (options[:context] || Groonga::Context.default)[type]
|
480
505
|
NORMALIZE_TYPE_TABLE[type] || type
|
481
506
|
end
|
482
507
|
end
|
@@ -515,7 +540,8 @@ module Groonga
|
|
515
540
|
# スキーマの内容を文字列で返す。返された値は
|
516
541
|
# Groonga::Schema#restoreすることによりスキーマ内に組み込むことができる。
|
517
542
|
def dump
|
518
|
-
dumper =
|
543
|
+
dumper = SchemaDumper.new(:context => @options[:context],
|
544
|
+
:syntax => @options[:syntax] || :ruby)
|
519
545
|
dumper.dump
|
520
546
|
end
|
521
547
|
|
@@ -1121,7 +1147,7 @@ module Groonga
|
|
1121
1147
|
key_support_table_common = {
|
1122
1148
|
:key_type => normalize_key_type(@options[:key_type] || "ShortText"),
|
1123
1149
|
:key_normalize => @options[:key_normalize],
|
1124
|
-
:default_tokenizer => @options[:default_tokenizer],
|
1150
|
+
:default_tokenizer => normalize_type(@options[:default_tokenizer]),
|
1125
1151
|
}
|
1126
1152
|
|
1127
1153
|
if @table_type == Groonga::Array
|
@@ -1181,7 +1207,9 @@ module Groonga
|
|
1181
1207
|
sub_records = false if sub_records.nil?
|
1182
1208
|
return false unless table.support_sub_records? == sub_records
|
1183
1209
|
path = options[:path]
|
1184
|
-
|
1210
|
+
if path and File.expand_path(table.path) != File.expand_path(path)
|
1211
|
+
return false
|
1212
|
+
end
|
1185
1213
|
|
1186
1214
|
case table
|
1187
1215
|
when Groonga::Array
|
@@ -1189,7 +1217,8 @@ module Groonga
|
|
1189
1217
|
when Groonga::Hash, Groonga::PatriciaTrie
|
1190
1218
|
key_type = normalize_key_type(options[:key_type])
|
1191
1219
|
return false unless table.domain == resolve_name(key_type)
|
1192
|
-
default_tokenizer =
|
1220
|
+
default_tokenizer = normalize_type(options[:default_tokenizer])
|
1221
|
+
default_tokenizer = resolve_name(default_tokenizer)
|
1193
1222
|
return false unless table.default_tokenizer == default_tokenizer
|
1194
1223
|
key_normalize = options[:key_normalize]
|
1195
1224
|
key_normalize = false if key_normalize.nil?
|
@@ -1206,7 +1235,11 @@ module Groonga
|
|
1206
1235
|
end
|
1207
1236
|
|
1208
1237
|
def normalize_key_type(key_type)
|
1209
|
-
|
1238
|
+
normalize_type(key_type || "ShortText")
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
def normalize_type(type)
|
1242
|
+
Schema.normalize_type(type, :context => context)
|
1210
1243
|
end
|
1211
1244
|
|
1212
1245
|
def resolve_name(type)
|
@@ -1250,13 +1283,20 @@ module Groonga
|
|
1250
1283
|
end
|
1251
1284
|
|
1252
1285
|
def define
|
1253
|
-
|
1254
|
-
table = context[@name]
|
1286
|
+
table = removed_table
|
1255
1287
|
dir = columns_directory_path(table)
|
1256
1288
|
result = table.remove
|
1257
1289
|
rmdir_if_dir_exists(dir)
|
1258
1290
|
result
|
1259
1291
|
end
|
1292
|
+
|
1293
|
+
private
|
1294
|
+
def removed_table
|
1295
|
+
context = @options[:context]
|
1296
|
+
table = context[@name]
|
1297
|
+
raise TableNotExists.new(@name) if table.nil?
|
1298
|
+
table
|
1299
|
+
end
|
1260
1300
|
end
|
1261
1301
|
|
1262
1302
|
# スキーマ定義時にGroonga::Schema.create_viewや
|
@@ -1382,7 +1422,7 @@ module Groonga
|
|
1382
1422
|
else
|
1383
1423
|
resolved_type = @type
|
1384
1424
|
end
|
1385
|
-
Schema.normalize_type(resolved_type)
|
1425
|
+
Schema.normalize_type(resolved_type, :context => context)
|
1386
1426
|
end
|
1387
1427
|
|
1388
1428
|
def same_column?(context, column)
|
@@ -1533,172 +1573,5 @@ module Groonga
|
|
1533
1573
|
File.join(columns_dir, name)
|
1534
1574
|
end
|
1535
1575
|
end
|
1536
|
-
|
1537
|
-
class Dumper # :nodoc:
|
1538
|
-
def initialize(options={})
|
1539
|
-
@options = (options || {}).dup
|
1540
|
-
end
|
1541
|
-
|
1542
|
-
def dump
|
1543
|
-
context = @options[:context] || Groonga::Context.default
|
1544
|
-
database = context.database
|
1545
|
-
return nil if database.nil?
|
1546
|
-
|
1547
|
-
header + dump_schema(database) + footer
|
1548
|
-
end
|
1549
|
-
|
1550
|
-
def dump_schema(database)
|
1551
|
-
index_columns = []
|
1552
|
-
reference_columns = []
|
1553
|
-
definitions = []
|
1554
|
-
database.each do |object|
|
1555
|
-
next unless object.is_a?(Groonga::Table)
|
1556
|
-
table = object
|
1557
|
-
schema = create_table_header(table)
|
1558
|
-
table.columns.sort_by {|column| column.local_name}.each do |column|
|
1559
|
-
if column.is_a?(Groonga::IndexColumn)
|
1560
|
-
index_columns << column
|
1561
|
-
else
|
1562
|
-
if column.range.is_a?(Groonga::Table)
|
1563
|
-
reference_columns << column
|
1564
|
-
else
|
1565
|
-
schema << define_column(table, column)
|
1566
|
-
end
|
1567
|
-
end
|
1568
|
-
end
|
1569
|
-
schema << create_table_footer(table)
|
1570
|
-
definitions << schema
|
1571
|
-
end
|
1572
|
-
|
1573
|
-
reference_columns.group_by do |column|
|
1574
|
-
column.table
|
1575
|
-
end.each do |table, columns|
|
1576
|
-
schema = change_table_header(table)
|
1577
|
-
columns.each do |column|
|
1578
|
-
schema << define_reference_column(table, column)
|
1579
|
-
end
|
1580
|
-
schema << change_table_footer(table)
|
1581
|
-
definitions << schema
|
1582
|
-
end
|
1583
|
-
|
1584
|
-
index_columns.group_by do |column|
|
1585
|
-
column.table
|
1586
|
-
end.each do |table, columns|
|
1587
|
-
schema = change_table_header(table)
|
1588
|
-
columns.each do |column|
|
1589
|
-
schema << define_index_column(table, column)
|
1590
|
-
end
|
1591
|
-
schema << change_table_footer(table)
|
1592
|
-
definitions << schema
|
1593
|
-
end
|
1594
|
-
|
1595
|
-
if definitions.empty?
|
1596
|
-
""
|
1597
|
-
else
|
1598
|
-
definitions.join("\n\n") + "\n"
|
1599
|
-
end
|
1600
|
-
end
|
1601
|
-
|
1602
|
-
private
|
1603
|
-
def header
|
1604
|
-
""
|
1605
|
-
end
|
1606
|
-
|
1607
|
-
def footer
|
1608
|
-
""
|
1609
|
-
end
|
1610
|
-
|
1611
|
-
def create_table_header(table)
|
1612
|
-
parameters = []
|
1613
|
-
unless table.is_a?(Groonga::Array)
|
1614
|
-
case table
|
1615
|
-
when Groonga::Hash
|
1616
|
-
parameters << ":type => :hash"
|
1617
|
-
when Groonga::PatriciaTrie
|
1618
|
-
parameters << ":type => :patricia_trie"
|
1619
|
-
end
|
1620
|
-
if table.domain
|
1621
|
-
parameters << ":key_type => #{table.domain.name.dump}"
|
1622
|
-
if table.normalize_key?
|
1623
|
-
parameters << ":key_normalize => true"
|
1624
|
-
end
|
1625
|
-
end
|
1626
|
-
default_tokenizer = table.default_tokenizer
|
1627
|
-
if default_tokenizer
|
1628
|
-
parameters << ":default_tokenizer => #{default_tokenizer.name.dump}"
|
1629
|
-
end
|
1630
|
-
end
|
1631
|
-
parameters << ":force => true"
|
1632
|
-
parameters.unshift("")
|
1633
|
-
parameters = parameters.join(",\n ")
|
1634
|
-
"create_table(#{table.name.dump}#{parameters}) do |table|\n"
|
1635
|
-
end
|
1636
|
-
|
1637
|
-
def create_table_footer(table)
|
1638
|
-
"end"
|
1639
|
-
end
|
1640
|
-
|
1641
|
-
def change_table_header(table)
|
1642
|
-
"change_table(#{table.name.inspect}) do |table|\n"
|
1643
|
-
end
|
1644
|
-
|
1645
|
-
def change_table_footer(table)
|
1646
|
-
"end"
|
1647
|
-
end
|
1648
|
-
|
1649
|
-
def define_column(table, column)
|
1650
|
-
type = column_method(column)
|
1651
|
-
name = column.local_name
|
1652
|
-
" table.#{type}(#{name.inspect})\n"
|
1653
|
-
end
|
1654
|
-
|
1655
|
-
def define_reference_column(table, column)
|
1656
|
-
name = column.local_name
|
1657
|
-
reference = column.range
|
1658
|
-
" table.reference(#{name.dump}, #{reference.name.dump})\n"
|
1659
|
-
end
|
1660
|
-
|
1661
|
-
def define_index_column(table, column)
|
1662
|
-
target_table_name = column.range.name
|
1663
|
-
sources = column.sources
|
1664
|
-
source_names = sources.collect do |source|
|
1665
|
-
if source.is_a?(table.class)
|
1666
|
-
"_key".dump
|
1667
|
-
else
|
1668
|
-
source.local_name.dump
|
1669
|
-
end
|
1670
|
-
end.join(", ")
|
1671
|
-
arguments = [target_table_name.dump,
|
1672
|
-
sources.size == 1 ? source_names : "[#{source_names}]",
|
1673
|
-
":name => #{column.local_name.dump}"]
|
1674
|
-
" table.index(#{arguments.join(', ')})\n"
|
1675
|
-
end
|
1676
|
-
|
1677
|
-
def column_method(column)
|
1678
|
-
range = column.range
|
1679
|
-
case range.name
|
1680
|
-
when "Int32"
|
1681
|
-
"integer32"
|
1682
|
-
when "Int64"
|
1683
|
-
"integer64"
|
1684
|
-
when "UInt32"
|
1685
|
-
"unsigned_integer32"
|
1686
|
-
when "UInt64"
|
1687
|
-
"unsigned_integer64"
|
1688
|
-
when "Float"
|
1689
|
-
"float"
|
1690
|
-
when "Time"
|
1691
|
-
"time"
|
1692
|
-
when "ShortText"
|
1693
|
-
"short_text"
|
1694
|
-
when "Text"
|
1695
|
-
"text"
|
1696
|
-
when "LongText"
|
1697
|
-
"long_text"
|
1698
|
-
else
|
1699
|
-
raise ArgumentError, "unsupported column: #{column.inspect}"
|
1700
|
-
end
|
1701
|
-
end
|
1702
|
-
end
|
1703
1576
|
end
|
1704
1577
|
end
|
data/rroonga-build.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
base_dir = Pathname(__FILE__).dirname.expand_path
|
6
|
+
test_unit_dir = (base_dir.parent + "test-unit").expand_path
|
7
|
+
test_unit_lib_dir = test_unit_dir + "lib"
|
8
|
+
lib_dir = base_dir + "lib"
|
9
|
+
|
10
|
+
$LOAD_PATH.unshift(test_unit_lib_dir.to_s)
|
11
|
+
$LOAD_PATH.unshift(lib_dir.to_s)
|
12
|
+
|
13
|
+
require 'test/unit/notify'
|
14
|
+
|
15
|
+
require 'rubygems'
|
16
|
+
require 'hoe'
|
17
|
+
|
18
|
+
Test::Unit.run = true
|
19
|
+
|
20
|
+
version = Test::Unit::Notify::VERSION
|
21
|
+
ENV["VERSION"] = version
|
22
|
+
Hoe.spec('test-unit-notify') do
|
23
|
+
self.version = version
|
24
|
+
self.rubyforge_name = "test-unit"
|
25
|
+
|
26
|
+
developer('Kouhei Sutou', 'kou@clear-code.com')
|
27
|
+
|
28
|
+
extra_deps << ["test-unit"]
|
29
|
+
end
|
30
|
+
|
31
|
+
task :docs do
|
32
|
+
doc_dir = base_dir + "doc"
|
33
|
+
doc_screenshot_dir = doc_dir + "screenshot"
|
34
|
+
mkdir_p(doc_screenshot_dir.to_s)
|
35
|
+
(base_dir + "screenshot").children.each do |file|
|
36
|
+
next if file.directory?
|
37
|
+
cp(file.to_s, doc_screenshot_dir.to_s)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :tag do
|
42
|
+
message = "Released Test::Unit::Notify #{version}!"
|
43
|
+
base = "svn+ssh://#{ENV['USER']}@rubyforge.org/var/svn/test-unit/extensions/test-unit-notify/"
|
44
|
+
sh 'svn', 'copy', '-m', message, "#{base}trunk", "#{base}tags/#{version}"
|
45
|
+
end
|
46
|
+
|
47
|
+
# vim: syntax=Ruby
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Author:: Kouhei Sutou
|
4
|
+
# Copyright::
|
5
|
+
# * Copyright (c) 2010 Kouhei Sutou <kou@clear-code.com>
|
6
|
+
# License:: Ruby license.
|
7
|
+
|
8
|
+
require 'pathname'
|
9
|
+
require 'erb'
|
10
|
+
require 'test/unit'
|
11
|
+
|
12
|
+
module Test
|
13
|
+
module Unit
|
14
|
+
AutoRunner.setup_option do |auto_runner, options|
|
15
|
+
options.on("--[no-]notify",
|
16
|
+
"Notify test result at the last.") do |use_notify|
|
17
|
+
auto_runner.listeners.reject! do |listener|
|
18
|
+
listener.is_a?(Notify::Notifier)
|
19
|
+
end
|
20
|
+
auto_runner.listeners << Notify::Notifier.new if use_notify
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Notify
|
25
|
+
VERSION = "0.0.2"
|
26
|
+
|
27
|
+
class Notifier
|
28
|
+
include ERB::Util
|
29
|
+
|
30
|
+
base_dir = Pathname(__FILE__).dirname.parent.parent.parent.expand_path
|
31
|
+
ICON_DIR = base_dir + "data" + "icons"
|
32
|
+
def initialize
|
33
|
+
@theme = "kinotan"
|
34
|
+
end
|
35
|
+
|
36
|
+
def attach_to_mediator(mediator)
|
37
|
+
mediator.add_listener(UI::TestRunnerMediator::STARTED,
|
38
|
+
&method(:started))
|
39
|
+
mediator.add_listener(UI::TestRunnerMediator::FINISHED,
|
40
|
+
&method(:finished))
|
41
|
+
end
|
42
|
+
|
43
|
+
def started(result)
|
44
|
+
@result = result
|
45
|
+
end
|
46
|
+
|
47
|
+
def finished(elapsed_time)
|
48
|
+
case RUBY_PLATFORM
|
49
|
+
when /mswin|mingw|cygwin/
|
50
|
+
# how?
|
51
|
+
when /darwin/
|
52
|
+
# growl?
|
53
|
+
else
|
54
|
+
notify_by_notify_send(elapsed_time)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def notify_by_notify_send(elapsed_time)
|
59
|
+
icon = guess_suitable_icon
|
60
|
+
args = ["notify-send",
|
61
|
+
"--expire-time", "5000",
|
62
|
+
"--urgency", urgency]
|
63
|
+
args.concat(["--icon", icon.to_s]) if icon
|
64
|
+
title = "%s [%g%%] (%gs)" % [@result.status,
|
65
|
+
@result.pass_percentage,
|
66
|
+
elapsed_time]
|
67
|
+
args << title
|
68
|
+
args << h(@result.summary)
|
69
|
+
system(*args)
|
70
|
+
end
|
71
|
+
|
72
|
+
def guess_suitable_icon
|
73
|
+
icon_dir = ICON_DIR + @theme
|
74
|
+
status = @result.status
|
75
|
+
icon_base_names = [status]
|
76
|
+
if @result.passed?
|
77
|
+
icon_base_names << "pass"
|
78
|
+
else
|
79
|
+
case status
|
80
|
+
when "failure"
|
81
|
+
icon_base_names << "error"
|
82
|
+
when "error"
|
83
|
+
icon_base_names << "failure"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
icon_base_names << "default"
|
87
|
+
icon_base_names.each do |base_name|
|
88
|
+
icon = icon_dir + "#{base_name}.png"
|
89
|
+
return icon if icon.exist?
|
90
|
+
end
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def urgency
|
95
|
+
if @result.passed?
|
96
|
+
"normal"
|
97
|
+
else
|
98
|
+
"critical"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|