rroonga 0.9.2-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. data/AUTHORS +5 -0
  2. data/NEWS.ja.rdoc +114 -0
  3. data/NEWS.rdoc +116 -0
  4. data/README.ja.rdoc +65 -0
  5. data/README.rdoc +66 -0
  6. data/Rakefile +206 -0
  7. data/benchmark/common.rb +49 -0
  8. data/benchmark/read-write-many-small-items.rb +144 -0
  9. data/benchmark/write-many-small-items.rb +135 -0
  10. data/example/bookmark.rb +161 -0
  11. data/example/index-html.rb +89 -0
  12. data/example/search/config.ru +230 -0
  13. data/example/search/public/css/groonga.css +122 -0
  14. data/ext/.gitignore +2 -0
  15. data/ext/groonga/extconf.rb +93 -0
  16. data/ext/groonga/rb-grn-accessor.c +52 -0
  17. data/ext/groonga/rb-grn-array-cursor.c +36 -0
  18. data/ext/groonga/rb-grn-array.c +210 -0
  19. data/ext/groonga/rb-grn-column.c +573 -0
  20. data/ext/groonga/rb-grn-context.c +662 -0
  21. data/ext/groonga/rb-grn-database.c +472 -0
  22. data/ext/groonga/rb-grn-encoding-support.c +64 -0
  23. data/ext/groonga/rb-grn-encoding.c +257 -0
  24. data/ext/groonga/rb-grn-exception.c +1110 -0
  25. data/ext/groonga/rb-grn-expression-builder.c +75 -0
  26. data/ext/groonga/rb-grn-expression.c +731 -0
  27. data/ext/groonga/rb-grn-fix-size-column.c +166 -0
  28. data/ext/groonga/rb-grn-hash-cursor.c +38 -0
  29. data/ext/groonga/rb-grn-hash.c +294 -0
  30. data/ext/groonga/rb-grn-index-column.c +488 -0
  31. data/ext/groonga/rb-grn-logger.c +504 -0
  32. data/ext/groonga/rb-grn-object.c +1369 -0
  33. data/ext/groonga/rb-grn-operation.c +198 -0
  34. data/ext/groonga/rb-grn-patricia-trie-cursor.c +39 -0
  35. data/ext/groonga/rb-grn-patricia-trie.c +488 -0
  36. data/ext/groonga/rb-grn-procedure.c +52 -0
  37. data/ext/groonga/rb-grn-query.c +260 -0
  38. data/ext/groonga/rb-grn-record.c +40 -0
  39. data/ext/groonga/rb-grn-snippet.c +334 -0
  40. data/ext/groonga/rb-grn-table-cursor-key-support.c +69 -0
  41. data/ext/groonga/rb-grn-table-cursor.c +247 -0
  42. data/ext/groonga/rb-grn-table-key-support.c +714 -0
  43. data/ext/groonga/rb-grn-table.c +1977 -0
  44. data/ext/groonga/rb-grn-type.c +181 -0
  45. data/ext/groonga/rb-grn-utils.c +769 -0
  46. data/ext/groonga/rb-grn-variable-size-column.c +36 -0
  47. data/ext/groonga/rb-grn-variable.c +108 -0
  48. data/ext/groonga/rb-grn-view-accessor.c +53 -0
  49. data/ext/groonga/rb-grn-view-cursor.c +35 -0
  50. data/ext/groonga/rb-grn-view-record.c +41 -0
  51. data/ext/groonga/rb-grn-view.c +421 -0
  52. data/ext/groonga/rb-grn.h +698 -0
  53. data/ext/groonga/rb-groonga.c +107 -0
  54. data/extconf.rb +130 -0
  55. data/html/bar.svg +153 -0
  56. data/html/developer.html +117 -0
  57. data/html/developer.svg +469 -0
  58. data/html/download.svg +253 -0
  59. data/html/favicon.ico +0 -0
  60. data/html/favicon.xcf +0 -0
  61. data/html/footer.html.erb +28 -0
  62. data/html/head.html.erb +4 -0
  63. data/html/header.html.erb +17 -0
  64. data/html/index.html +147 -0
  65. data/html/install.svg +636 -0
  66. data/html/logo.xcf +0 -0
  67. data/html/ranguba.css +250 -0
  68. data/html/tutorial.svg +559 -0
  69. data/lib/1.8/groonga.so +0 -0
  70. data/lib/1.9/groonga.so +0 -0
  71. data/lib/groonga.rb +90 -0
  72. data/lib/groonga/context.rb +184 -0
  73. data/lib/groonga/expression-builder.rb +324 -0
  74. data/lib/groonga/patricia-trie.rb +85 -0
  75. data/lib/groonga/record.rb +311 -0
  76. data/lib/groonga/schema.rb +1191 -0
  77. data/lib/groonga/view-record.rb +56 -0
  78. data/license/GPL +340 -0
  79. data/license/LGPL +504 -0
  80. data/license/RUBY +59 -0
  81. data/misc/grnop2ruby.rb +49 -0
  82. data/pkg-config.rb +333 -0
  83. data/rroonga-build.rb +57 -0
  84. data/test-unit/Rakefile +40 -0
  85. data/test-unit/TODO +5 -0
  86. data/test-unit/bin/testrb +5 -0
  87. data/test-unit/html/classic.html +15 -0
  88. data/test-unit/html/index.html +25 -0
  89. data/test-unit/html/index.html.ja +27 -0
  90. data/test-unit/lib/test/unit.rb +323 -0
  91. data/test-unit/lib/test/unit/assertionfailederror.rb +25 -0
  92. data/test-unit/lib/test/unit/assertions.rb +1230 -0
  93. data/test-unit/lib/test/unit/attribute.rb +125 -0
  94. data/test-unit/lib/test/unit/autorunner.rb +360 -0
  95. data/test-unit/lib/test/unit/collector.rb +36 -0
  96. data/test-unit/lib/test/unit/collector/descendant.rb +23 -0
  97. data/test-unit/lib/test/unit/collector/dir.rb +108 -0
  98. data/test-unit/lib/test/unit/collector/load.rb +144 -0
  99. data/test-unit/lib/test/unit/collector/objectspace.rb +34 -0
  100. data/test-unit/lib/test/unit/color-scheme.rb +102 -0
  101. data/test-unit/lib/test/unit/color.rb +96 -0
  102. data/test-unit/lib/test/unit/diff.rb +724 -0
  103. data/test-unit/lib/test/unit/error.rb +130 -0
  104. data/test-unit/lib/test/unit/exceptionhandler.rb +39 -0
  105. data/test-unit/lib/test/unit/failure.rb +136 -0
  106. data/test-unit/lib/test/unit/fixture.rb +176 -0
  107. data/test-unit/lib/test/unit/notification.rb +129 -0
  108. data/test-unit/lib/test/unit/omission.rb +191 -0
  109. data/test-unit/lib/test/unit/pending.rb +150 -0
  110. data/test-unit/lib/test/unit/priority.rb +180 -0
  111. data/test-unit/lib/test/unit/runner/console.rb +52 -0
  112. data/test-unit/lib/test/unit/runner/emacs.rb +8 -0
  113. data/test-unit/lib/test/unit/runner/tap.rb +8 -0
  114. data/test-unit/lib/test/unit/testcase.rb +476 -0
  115. data/test-unit/lib/test/unit/testresult.rb +89 -0
  116. data/test-unit/lib/test/unit/testsuite.rb +110 -0
  117. data/test-unit/lib/test/unit/ui/console/outputlevel.rb +14 -0
  118. data/test-unit/lib/test/unit/ui/console/testrunner.rb +466 -0
  119. data/test-unit/lib/test/unit/ui/emacs/testrunner.rb +63 -0
  120. data/test-unit/lib/test/unit/ui/tap/testrunner.rb +92 -0
  121. data/test-unit/lib/test/unit/ui/testrunner.rb +28 -0
  122. data/test-unit/lib/test/unit/ui/testrunnermediator.rb +77 -0
  123. data/test-unit/lib/test/unit/ui/testrunnerutilities.rb +41 -0
  124. data/test-unit/lib/test/unit/util/backtracefilter.rb +41 -0
  125. data/test-unit/lib/test/unit/util/method-owner-finder.rb +28 -0
  126. data/test-unit/lib/test/unit/util/observable.rb +90 -0
  127. data/test-unit/lib/test/unit/util/procwrapper.rb +48 -0
  128. data/test-unit/lib/test/unit/version.rb +7 -0
  129. data/test-unit/sample/adder.rb +13 -0
  130. data/test-unit/sample/subtracter.rb +12 -0
  131. data/test-unit/sample/test_adder.rb +20 -0
  132. data/test-unit/sample/test_subtracter.rb +20 -0
  133. data/test-unit/sample/test_user.rb +23 -0
  134. data/test-unit/test/collector/test-descendant.rb +133 -0
  135. data/test-unit/test/collector/test-load.rb +442 -0
  136. data/test-unit/test/collector/test_dir.rb +406 -0
  137. data/test-unit/test/collector/test_objectspace.rb +100 -0
  138. data/test-unit/test/run-test.rb +15 -0
  139. data/test-unit/test/test-attribute.rb +86 -0
  140. data/test-unit/test/test-color-scheme.rb +67 -0
  141. data/test-unit/test/test-color.rb +47 -0
  142. data/test-unit/test/test-diff.rb +518 -0
  143. data/test-unit/test/test-emacs-runner.rb +60 -0
  144. data/test-unit/test/test-fixture.rb +287 -0
  145. data/test-unit/test/test-notification.rb +33 -0
  146. data/test-unit/test/test-omission.rb +81 -0
  147. data/test-unit/test/test-pending.rb +70 -0
  148. data/test-unit/test/test-priority.rb +119 -0
  149. data/test-unit/test/test-testcase.rb +544 -0
  150. data/test-unit/test/test_assertions.rb +1151 -0
  151. data/test-unit/test/test_error.rb +26 -0
  152. data/test-unit/test/test_failure.rb +33 -0
  153. data/test-unit/test/test_testresult.rb +113 -0
  154. data/test-unit/test/test_testsuite.rb +129 -0
  155. data/test-unit/test/testunit-test-util.rb +14 -0
  156. data/test-unit/test/ui/test_testrunmediator.rb +20 -0
  157. data/test-unit/test/util/test-method-owner-finder.rb +38 -0
  158. data/test-unit/test/util/test_backtracefilter.rb +41 -0
  159. data/test-unit/test/util/test_observable.rb +102 -0
  160. data/test-unit/test/util/test_procwrapper.rb +36 -0
  161. data/test/.gitignore +1 -0
  162. data/test/groonga-test-utils.rb +134 -0
  163. data/test/run-test.rb +58 -0
  164. data/test/test-array.rb +90 -0
  165. data/test/test-column.rb +316 -0
  166. data/test/test-context-select.rb +93 -0
  167. data/test/test-context.rb +73 -0
  168. data/test/test-database.rb +113 -0
  169. data/test/test-encoding.rb +33 -0
  170. data/test/test-exception.rb +93 -0
  171. data/test/test-expression-builder.rb +217 -0
  172. data/test/test-expression.rb +134 -0
  173. data/test/test-fix-size-column.rb +65 -0
  174. data/test/test-gqtp.rb +72 -0
  175. data/test/test-hash.rb +305 -0
  176. data/test/test-index-column.rb +81 -0
  177. data/test/test-logger.rb +37 -0
  178. data/test/test-patricia-trie.rb +205 -0
  179. data/test/test-procedure.rb +37 -0
  180. data/test/test-query.rb +22 -0
  181. data/test/test-record.rb +243 -0
  182. data/test/test-remote.rb +54 -0
  183. data/test/test-schema-view.rb +90 -0
  184. data/test/test-schema.rb +459 -0
  185. data/test/test-snippet.rb +130 -0
  186. data/test/test-table-cursor.rb +153 -0
  187. data/test/test-table-offset-and-limit.rb +102 -0
  188. data/test/test-table-select-normalize.rb +53 -0
  189. data/test/test-table-select.rb +150 -0
  190. data/test/test-table.rb +594 -0
  191. data/test/test-type.rb +71 -0
  192. data/test/test-variable-size-column.rb +98 -0
  193. data/test/test-variable.rb +28 -0
  194. data/test/test-vector-column.rb +76 -0
  195. data/test/test-version.rb +31 -0
  196. data/test/test-view.rb +72 -0
  197. data/text/TUTORIAL.ja.rdoc +392 -0
  198. data/text/expression.rdoc +284 -0
  199. metadata +276 -0
@@ -0,0 +1,198 @@
1
+ /* -*- c-file-style: "ruby" -*- */
2
+ /*
3
+ Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
4
+
5
+ This library is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License version 2.1 as published by the Free Software Foundation.
8
+
9
+ This library is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ Lesser General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Lesser General Public
15
+ License along with this library; if not, write to the Free Software
16
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ */
18
+
19
+ #include "rb-grn.h"
20
+
21
+ VALUE rb_mGrnOperation;
22
+
23
+ void
24
+ rb_grn_init_operation (VALUE mGrn)
25
+ {
26
+ rb_mGrnOperation = rb_define_module_under(mGrn, "Operation");
27
+
28
+ rb_define_const(rb_mGrnOperation, "PUSH",
29
+ UINT2NUM(GRN_OP_PUSH));
30
+ rb_define_const(rb_mGrnOperation, "POP",
31
+ UINT2NUM(GRN_OP_POP));
32
+ rb_define_const(rb_mGrnOperation, "NO_OPERATION",
33
+ UINT2NUM(GRN_OP_NOP));
34
+ rb_define_const(rb_mGrnOperation, "CALL",
35
+ UINT2NUM(GRN_OP_CALL));
36
+ rb_define_const(rb_mGrnOperation, "INTERN",
37
+ UINT2NUM(GRN_OP_INTERN));
38
+ rb_define_const(rb_mGrnOperation, "GET_REFERENCE",
39
+ UINT2NUM(GRN_OP_GET_REF));
40
+ rb_define_const(rb_mGrnOperation, "GET_VALUE",
41
+ UINT2NUM(GRN_OP_GET_VALUE));
42
+ rb_define_const(rb_mGrnOperation, "AND",
43
+ UINT2NUM(GRN_OP_AND));
44
+ rb_define_const(rb_mGrnOperation, "BUT",
45
+ UINT2NUM(GRN_OP_BUT));
46
+ rb_define_const(rb_mGrnOperation, "OR",
47
+ UINT2NUM(GRN_OP_OR));
48
+ rb_define_const(rb_mGrnOperation, "ASSIGN",
49
+ UINT2NUM(GRN_OP_ASSIGN));
50
+ rb_define_const(rb_mGrnOperation, "STAR_ASSIGN",
51
+ UINT2NUM(GRN_OP_STAR_ASSIGN));
52
+ rb_define_const(rb_mGrnOperation, "SLASH_ASSIGN",
53
+ UINT2NUM(GRN_OP_SLASH_ASSIGN));
54
+ rb_define_const(rb_mGrnOperation, "MODULO_ASSIGN",
55
+ UINT2NUM(GRN_OP_MOD_ASSIGN));
56
+ rb_define_const(rb_mGrnOperation, "PLUS_ASSIGN",
57
+ UINT2NUM(GRN_OP_PLUS_ASSIGN));
58
+ rb_define_const(rb_mGrnOperation, "MINUS_ASSIGN",
59
+ UINT2NUM(GRN_OP_MINUS_ASSIGN));
60
+ rb_define_const(rb_mGrnOperation, "SHIFTL_ASSIGN",
61
+ UINT2NUM(GRN_OP_SHIFTL_ASSIGN));
62
+ rb_define_const(rb_mGrnOperation, "SHIRTR_ASSIGN",
63
+ UINT2NUM(GRN_OP_SHIFTR_ASSIGN));
64
+ rb_define_const(rb_mGrnOperation, "SHIFTRR_ASSIGN",
65
+ UINT2NUM(GRN_OP_SHIFTRR_ASSIGN));
66
+ rb_define_const(rb_mGrnOperation, "AND_ASSIGN",
67
+ UINT2NUM(GRN_OP_AND_ASSIGN));
68
+ rb_define_const(rb_mGrnOperation, "XOR_ASSIGN",
69
+ UINT2NUM(GRN_OP_XOR_ASSIGN));
70
+ rb_define_const(rb_mGrnOperation, "OR_ASSIGN",
71
+ UINT2NUM(GRN_OP_OR_ASSIGN));
72
+ rb_define_const(rb_mGrnOperation, "JUMP",
73
+ UINT2NUM(GRN_OP_JUMP));
74
+ rb_define_const(rb_mGrnOperation, "CJUMP",
75
+ UINT2NUM(GRN_OP_CJUMP));
76
+ rb_define_const(rb_mGrnOperation, "COMMA",
77
+ UINT2NUM(GRN_OP_COMMA));
78
+ rb_define_const(rb_mGrnOperation, "BITWISE_OR",
79
+ UINT2NUM(GRN_OP_BITWISE_OR));
80
+ rb_define_const(rb_mGrnOperation, "BITWISE_XOR",
81
+ UINT2NUM(GRN_OP_BITWISE_XOR));
82
+ rb_define_const(rb_mGrnOperation, "BITWISE_AND",
83
+ UINT2NUM(GRN_OP_BITWISE_AND));
84
+ rb_define_const(rb_mGrnOperation, "BITWISE_NOT",
85
+ UINT2NUM(GRN_OP_BITWISE_NOT));
86
+ rb_define_const(rb_mGrnOperation, "EQUAL",
87
+ UINT2NUM(GRN_OP_EQUAL));
88
+ rb_define_const(rb_mGrnOperation, "NOT_EQUAL",
89
+ UINT2NUM(GRN_OP_NOT_EQUAL));
90
+ rb_define_const(rb_mGrnOperation, "LESS",
91
+ UINT2NUM(GRN_OP_LESS));
92
+ rb_define_const(rb_mGrnOperation, "GREATER",
93
+ UINT2NUM(GRN_OP_GREATER));
94
+ rb_define_const(rb_mGrnOperation, "LESS_EQUAL",
95
+ UINT2NUM(GRN_OP_LESS_EQUAL));
96
+ rb_define_const(rb_mGrnOperation, "GREATER_EQUAL",
97
+ UINT2NUM(GRN_OP_GREATER_EQUAL));
98
+ rb_define_const(rb_mGrnOperation, "IN",
99
+ UINT2NUM(GRN_OP_IN));
100
+ rb_define_const(rb_mGrnOperation, "MATCH",
101
+ UINT2NUM(GRN_OP_MATCH));
102
+ rb_define_const(rb_mGrnOperation, "NEAR",
103
+ UINT2NUM(GRN_OP_NEAR));
104
+ rb_define_const(rb_mGrnOperation, "NEAR2",
105
+ UINT2NUM(GRN_OP_NEAR2));
106
+ rb_define_const(rb_mGrnOperation, "SIMILAR",
107
+ UINT2NUM(GRN_OP_SIMILAR));
108
+ rb_define_const(rb_mGrnOperation, "TERM_EXTRACT",
109
+ UINT2NUM(GRN_OP_TERM_EXTRACT));
110
+ rb_define_const(rb_mGrnOperation, "SHIFTL",
111
+ UINT2NUM(GRN_OP_SHIFTL));
112
+ rb_define_const(rb_mGrnOperation, "SHIFTR",
113
+ UINT2NUM(GRN_OP_SHIFTR));
114
+ rb_define_const(rb_mGrnOperation, "SHIFTRR",
115
+ UINT2NUM(GRN_OP_SHIFTRR));
116
+ rb_define_const(rb_mGrnOperation, "PLUS",
117
+ UINT2NUM(GRN_OP_PLUS));
118
+ rb_define_const(rb_mGrnOperation, "MINUS",
119
+ UINT2NUM(GRN_OP_MINUS));
120
+ rb_define_const(rb_mGrnOperation, "STAR",
121
+ UINT2NUM(GRN_OP_STAR));
122
+ rb_define_const(rb_mGrnOperation, "SLASH",
123
+ UINT2NUM(GRN_OP_SLASH));
124
+ rb_define_const(rb_mGrnOperation, "MODULO",
125
+ UINT2NUM(GRN_OP_MOD));
126
+ rb_define_const(rb_mGrnOperation, "DELETE",
127
+ UINT2NUM(GRN_OP_DELETE));
128
+ rb_define_const(rb_mGrnOperation, "INCREMENT",
129
+ UINT2NUM(GRN_OP_INCR));
130
+ rb_define_const(rb_mGrnOperation, "DECREMENT",
131
+ UINT2NUM(GRN_OP_DECR));
132
+ rb_define_const(rb_mGrnOperation, "INCREMENT_POST",
133
+ UINT2NUM(GRN_OP_INCR_POST));
134
+ rb_define_const(rb_mGrnOperation, "DECREMENT_POST",
135
+ UINT2NUM(GRN_OP_DECR_POST));
136
+ rb_define_const(rb_mGrnOperation, "NOT",
137
+ UINT2NUM(GRN_OP_NOT));
138
+ rb_define_const(rb_mGrnOperation, "ADJUST",
139
+ UINT2NUM(GRN_OP_ADJUST));
140
+ rb_define_const(rb_mGrnOperation, "EXACT",
141
+ UINT2NUM(GRN_OP_EXACT));
142
+ rb_define_const(rb_mGrnOperation, "LONGEST_COMMON_PREFIX",
143
+ UINT2NUM(GRN_OP_LCP));
144
+ rb_define_const(rb_mGrnOperation, "PARTIAL",
145
+ UINT2NUM(GRN_OP_PARTIAL));
146
+ rb_define_const(rb_mGrnOperation, "UNSPLIT",
147
+ UINT2NUM(GRN_OP_UNSPLIT));
148
+ rb_define_const(rb_mGrnOperation, "PREFIX",
149
+ UINT2NUM(GRN_OP_PREFIX));
150
+ rb_define_const(rb_mGrnOperation, "SUFFIX",
151
+ UINT2NUM(GRN_OP_SUFFIX));
152
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE1",
153
+ UINT2NUM(GRN_OP_GEO_DISTANCE1));
154
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE2",
155
+ UINT2NUM(GRN_OP_GEO_DISTANCE2));
156
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE3",
157
+ UINT2NUM(GRN_OP_GEO_DISTANCE3));
158
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE4",
159
+ UINT2NUM(GRN_OP_GEO_DISTANCE4));
160
+ rb_define_const(rb_mGrnOperation, "GEO_WITHINP5",
161
+ UINT2NUM(GRN_OP_GEO_WITHINP5));
162
+ rb_define_const(rb_mGrnOperation, "GEO_WITHINP6",
163
+ UINT2NUM(GRN_OP_GEO_WITHINP6));
164
+ rb_define_const(rb_mGrnOperation, "GEO_WITHINP8",
165
+ UINT2NUM(GRN_OP_GEO_WITHINP8));
166
+ rb_define_const(rb_mGrnOperation, "OBJECT_SEARCH",
167
+ UINT2NUM(GRN_OP_OBJ_SEARCH));
168
+ rb_define_const(rb_mGrnOperation, "EXPRESSION_GET_VARIABLE",
169
+ UINT2NUM(GRN_OP_EXPR_GET_VAR));
170
+ rb_define_const(rb_mGrnOperation, "TABLE_CREATE",
171
+ UINT2NUM(GRN_OP_TABLE_CREATE));
172
+ rb_define_const(rb_mGrnOperation, "TABLE_SELECT",
173
+ UINT2NUM(GRN_OP_TABLE_SELECT));
174
+ rb_define_const(rb_mGrnOperation, "TABLE_SORT",
175
+ UINT2NUM(GRN_OP_TABLE_SORT));
176
+ rb_define_const(rb_mGrnOperation, "TABLE_GROUP",
177
+ UINT2NUM(GRN_OP_TABLE_GROUP));
178
+ rb_define_const(rb_mGrnOperation, "JSON_PUT",
179
+ UINT2NUM(GRN_OP_JSON_PUT));
180
+
181
+
182
+ /*
183
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE1",
184
+ UINT2NUM(GRN_OP_GEO_DISTANCE1));
185
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE2",
186
+ UINT2NUM(GRN_OP_GEO_DISTANCE2));
187
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE3",
188
+ UINT2NUM(GRN_OP_GEO_DISTANCE3));
189
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE4",
190
+ UINT2NUM(GRN_OP_GEO_DISTANCE4));
191
+ rb_define_const(rb_mGrnOperation, "GEO_WITHINP5",
192
+ UINT2NUM(GRN_OP_GEO_WITHINP5));
193
+ rb_define_const(rb_mGrnOperation, "GEO_WITHINP6",
194
+ UINT2NUM(GRN_OP_GEO_WITHINP6));
195
+ rb_define_const(rb_mGrnOperation, "GEO_WITHINP8",
196
+ UINT2NUM(GRN_OP_GEO_WITHINP8));
197
+ */
198
+ }
@@ -0,0 +1,39 @@
1
+ /* -*- c-file-style: "ruby" -*- */
2
+ /*
3
+ Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
4
+
5
+ This library is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License version 2.1 as published by the Free Software Foundation.
8
+
9
+ This library is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ Lesser General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Lesser General Public
15
+ License along with this library; if not, write to the Free Software
16
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ */
18
+
19
+ #include "rb-grn.h"
20
+
21
+ VALUE rb_cGrnPatriciaTrieCursor;
22
+
23
+ /*
24
+ * Document-class: Groonga::PatriciaTrieCursor < Groonga::TableCursor
25
+ *
26
+ * Groonga::PatriciaTrieに登録されているレコードを順番に取り
27
+ * 出すためのオブジェクト。利用できるメソッドは
28
+ * Groonga::TableCursorとGroonga::TableCursor::KeySupportを
29
+ * 参照。
30
+ */
31
+
32
+ void
33
+ rb_grn_init_patricia_trie_cursor (VALUE mGrn)
34
+ {
35
+ rb_cGrnPatriciaTrieCursor =
36
+ rb_define_class_under(mGrn, "PatriciaTrieCursor", rb_cGrnTableCursor);
37
+
38
+ rb_include_module(rb_cGrnPatriciaTrieCursor, rb_mGrnTableCursorKeySupport);
39
+ }
@@ -0,0 +1,488 @@
1
+ /* -*- c-file-style: "ruby" -*- */
2
+ /* vim: set sts=4 sw=4 ts=8 noet: */
3
+ /*
4
+ Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
5
+
6
+ This library is free software; you can redistribute it and/or
7
+ modify it under the terms of the GNU Lesser General Public
8
+ License version 2.1 as published by the Free Software Foundation.
9
+
10
+ This library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public
16
+ License along with this library; if not, write to the Free Software
17
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ */
19
+
20
+ #include "rb-grn.h"
21
+
22
+ #define SELF(object) ((RbGrnTableKeySupport *)DATA_PTR(object))
23
+
24
+ VALUE rb_cGrnPatriciaTrie;
25
+
26
+ /*
27
+ * Document-class: Groonga::PatriciaTrie < Groonga::Table
28
+ *
29
+ * 各レコードをパトリシアトライで管理するテーブル。ハッシュ
30
+ * テーブルに比べて完全一致検索の速度がやや遅いが、前方一致
31
+ * 検索・共通接頭辞探索などの検索ができる。またカーソルを用
32
+ * いてキーの昇降順にレコードを取り出すことができる。
33
+ */
34
+
35
+ /*
36
+ * call-seq:
37
+ * Groonga::PatriciaTrie.create(options={}) -> Groonga::PatriciaTrie
38
+ * Groonga::PatriciaTrie.create(options={}) {|table| ... }
39
+ *
40
+ * 各レコードをパトリシアトライで管理するテーブルを生成する。
41
+ * ブロックを指定すると、そのブロックに生成したテーブルが渡さ
42
+ * れ、ブロックを抜けると自動的にテーブルが破棄される。
43
+ *
44
+ * _options_に指定可能な値は以下の通り。
45
+ *
46
+ * [+:context+]
47
+ * テーブルが利用するGroonga::Context。省略すると
48
+ * Groonga::Context.defaultを用いる。
49
+ *
50
+ * [+:name+]
51
+ * テーブルの名前。名前をつけると、Groonga::Context#[]に名
52
+ * 前を指定してテーブルを取得することができる。省略すると
53
+ * 無名テーブルになり、テーブルIDでのみ取得できる。
54
+ *
55
+ * [+:path+]
56
+ * テーブルを保存するパス。パスを指定すると永続テーブルとな
57
+ * り、プロセス終了後もレコードは保持される。次回起動時に
58
+ * Groonga::Context#[]で保存されたレコードを利用する
59
+ * ことができる。省略すると一時テーブルになり、プロセスが終
60
+ * 了するとレコードは破棄される。
61
+ *
62
+ * [+:persistent+]
63
+ * +true+を指定すると永続テーブルとなる。+path+を省略した
64
+ * 場合は自動的にパスが付加される。+:context+で指定した
65
+ * Groonga::Contextに結びついているデータベースが一時デー
66
+ * タベースの場合は例外が発生する。
67
+ *
68
+ * [+:key_normalize+]
69
+ * +true+を指定するとキーを正規化する。
70
+ *
71
+ * [+:key_with_sis+]
72
+ * +true+を指定するとキーの文字列の全suffixが自動的に登
73
+ * 録される。
74
+ *
75
+ * [+:key_type+]
76
+ * キーの種類を示すオブジェクトを指定する。キーの種類には型
77
+ * 名("Int32"や"ShortText"など)またはGroonga::Typeまたは
78
+ * テーブル(Groonga::Array、Groonga::Hash、
79
+ * Groonga::PatriciaTrieのどれか)を指定する。
80
+ *
81
+ * Groonga::Typeを指定した場合は、その型が示す範囲の値をキー
82
+ * として使用する。ただし、キーの最大サイズは4096バイトで
83
+ * あるため、Groonga::Type::TEXTやGroonga::Type::LONG_TEXT
84
+ * は使用できない。
85
+ *
86
+ * テーブルを指定した場合はレコードIDをキーとして使用する。
87
+ * 指定したテーブルのGroonga::Recordをキーとして使用するこ
88
+ * ともでき、その場合は自動的にGroonga::Recordからレコード
89
+ * IDを取得する。
90
+ *
91
+ * 省略した場合は文字列をキーとして使用する。この場合、
92
+ * 4096バイトまで使用可能である。
93
+ *
94
+ * [+:value_type+]
95
+ * 値の型を指定する。省略すると値のための領域を確保しない。
96
+ * 値を保存したい場合は必ず指定すること。
97
+ *
98
+ * 参考: Groonga::Type.new
99
+ *
100
+ * [+:default_tokenizer+]
101
+ * Groonga::IndexColumnで使用するトークナイザを指定する。
102
+ * デフォルトでは何も設定されていないので、テーブルに
103
+ * Groonga::IndexColumnを定義する場合は
104
+ * <tt>"TokenBigram"</tt>などを指定する必要がある。
105
+ *
106
+ * [+:sub_records+]
107
+ * +true+を指定すると#groupでグループ化したときに、
108
+ * Groonga::Record#n_sub_recordsでグループに含まれるレコー
109
+ * ドの件数を取得できる。
110
+ *
111
+ * 使用例:
112
+ *
113
+ * 無名一時テーブルを生成する。
114
+ * Groonga::PatriciaTrie.create
115
+ *
116
+ * 無名永続テーブルを生成する。
117
+ * Groonga::PatriciaTrie.create(:path => "/tmp/hash.grn")
118
+ *
119
+ * 名前付き永続テーブルを生成する。ただし、ファイル名は気に
120
+ * しない。
121
+ * Groonga::PatriciaTrie.create(:name => "Bookmarks",
122
+ * :persistent => true)
123
+ *
124
+ * それぞれのレコードに512バイトの値を格納できる無名一時テー
125
+ * ブルを生成する。
126
+ * Groonga::PatriciaTrie.create(:value => 512)
127
+ *
128
+ * キーとして文字列を使用する無名一時テーブルを生成する。
129
+ * Groonga::PatriciaTrie.create(:key_type => Groonga::Type::SHORT_TEXT)
130
+ *
131
+ * キーとして文字列を使用する無名一時テーブルを生成する。
132
+ * (キーの種類を表すオブジェクトは文字列で指定。)
133
+ * Groonga::PatriciaTrie.create(:key_type => "ShortText")
134
+ *
135
+ * キーとして<tt>Bookmarks</tt>テーブルのレコードを使用す
136
+ * る無名一時テーブルを生成する。
137
+ * bookmarks = Groonga::PatriciaTrie.create(:name => "Bookmarks")
138
+ * Groonga::PatriciaTrie.create(:key_type => bookmarks)
139
+ *
140
+ * キーとして<tt>Bookmarks</tt>テーブルのレコードを使用す
141
+ * る無名一時テーブルを生成する。
142
+ * (テーブルは文字列で指定。)
143
+ * Groonga::PatriciaTrie.create(:name => "Bookmarks")
144
+ * Groonga::PatriciaTrie.create(:key_type => "Bookmarks")
145
+ *
146
+ * 全文検索用のトークンをバイグラムで切り出す無名一時テーブ
147
+ * ルを生成する。
148
+ * bookmarks = Groonga::PatriciaTrie.create(:name => "Bookmarks")
149
+ * bookmarks.define_column("comment", "Text")
150
+ * terms = Groonga::PatriciaTrie.create(:name => "Terms",
151
+ * :default_tokenizer => "TokenBigram")
152
+ * terms.define_index_column("content", bookmarks,
153
+ * :source => "Bookmarks.comment")
154
+ */
155
+ static VALUE
156
+ rb_grn_patricia_trie_s_create (int argc, VALUE *argv, VALUE klass)
157
+ {
158
+ grn_ctx *context;
159
+ grn_obj *key_type = NULL, *value_type = NULL, *table;
160
+ const char *name = NULL, *path = NULL;
161
+ unsigned name_size = 0;
162
+ grn_obj_flags flags = GRN_TABLE_PAT_KEY;
163
+ VALUE rb_table;
164
+ VALUE options, rb_context, rb_name, rb_path, rb_persistent;
165
+ VALUE rb_key_normalize, rb_key_with_sis, rb_key_type;
166
+ VALUE rb_value_type;
167
+ VALUE rb_default_tokenizer, rb_sub_records;
168
+
169
+ rb_scan_args(argc, argv, "01", &options);
170
+
171
+ rb_grn_scan_options(options,
172
+ "context", &rb_context,
173
+ "name", &rb_name,
174
+ "path", &rb_path,
175
+ "persistent", &rb_persistent,
176
+ "key_normalize", &rb_key_normalize,
177
+ "key_with_sis", &rb_key_with_sis,
178
+ "key_type", &rb_key_type,
179
+ "value_type", &rb_value_type,
180
+ "default_tokenizer", &rb_default_tokenizer,
181
+ "sub_records", &rb_sub_records,
182
+ NULL);
183
+
184
+ context = rb_grn_context_ensure(&rb_context);
185
+
186
+ if (!NIL_P(rb_name)) {
187
+ name = StringValuePtr(rb_name);
188
+ name_size = RSTRING_LEN(rb_name);
189
+ flags |= GRN_OBJ_PERSISTENT;
190
+ }
191
+
192
+ if (!NIL_P(rb_path)) {
193
+ path = StringValueCStr(rb_path);
194
+ flags |= GRN_OBJ_PERSISTENT;
195
+ }
196
+
197
+ if (RVAL2CBOOL(rb_persistent))
198
+ flags |= GRN_OBJ_PERSISTENT;
199
+
200
+ if (RVAL2CBOOL(rb_key_normalize))
201
+ flags |= GRN_OBJ_KEY_NORMALIZE;
202
+
203
+ if (RVAL2CBOOL(rb_key_with_sis))
204
+ flags |= GRN_OBJ_KEY_WITH_SIS;
205
+
206
+ if (NIL_P(rb_key_type)) {
207
+ flags |= GRN_OBJ_KEY_VAR_SIZE;
208
+ } else {
209
+ key_type = RVAL2GRNOBJECT(rb_key_type, &context);
210
+ }
211
+
212
+ if (!NIL_P(rb_value_type))
213
+ value_type = RVAL2GRNOBJECT(rb_value_type, &context);
214
+
215
+ if (RVAL2CBOOL(rb_sub_records))
216
+ flags |= GRN_OBJ_WITH_SUBREC;
217
+
218
+ table = grn_table_create(context, name, name_size, path,
219
+ flags, key_type, value_type);
220
+ if (!table)
221
+ rb_grn_context_check(context, rb_ary_new4(argc, argv));
222
+ rb_table = GRNOBJECT2RVAL(klass, context, table, RB_GRN_TRUE);
223
+
224
+ if (!NIL_P(rb_default_tokenizer))
225
+ rb_funcall(rb_table, rb_intern("default_tokenizer="), 1,
226
+ rb_default_tokenizer);
227
+
228
+ if (rb_block_given_p())
229
+ return rb_ensure(rb_yield, rb_table, rb_grn_object_close, rb_table);
230
+ else
231
+ return rb_table;
232
+ }
233
+
234
+ /*
235
+ * call-seq:
236
+ * patricia_trie.search(key, options=nil) -> Groonga::Hash
237
+ *
238
+ * _key_にマッチするレコードのIDがキーに入っている
239
+ * Groonga::Hashを返す。マッチするレコードがない場合は空の
240
+ * Groonga::Hashが返る。
241
+ *
242
+ * _options_で+:result+を指定することにより、そのテーブルにマッ
243
+ * チしたレコードIDがキーのレコードを追加することができる。
244
+ * +:result+にテーブルを指定した場合は、そのテーブルが返る。
245
+ *
246
+ * _options_に指定可能な値は以下の通り。
247
+ *
248
+ * [+:result+]
249
+ * 結果を格納するテーブル。
250
+ *
251
+ * [+:operator+]
252
+ * マッチしたレコードをどのように扱うか。指定可能な値は以
253
+ * 下の通り。省略した場合はGroonga::Operation::OR。
254
+ *
255
+ * [Groonga::Operation::OR]
256
+ * マッチしたレコードを追加。すでにレコードが追加され
257
+ * ている場合は何もしない。
258
+ * [Groonga::Operation::AND]
259
+ * マッチしたレコードのスコアを増加。マッチしなかった
260
+ * レコードを削除。
261
+ * [Groonga::Operation::BUT]
262
+ * マッチしたレコードを削除。
263
+ * [Groonga::Operation::ADJUST]
264
+ * マッチしたレコードのスコアを増加。
265
+ *
266
+ * [+:type+]
267
+ * ?????
268
+ *
269
+ * 複数のキーで検索し、結果を1つのテーブルに集める。
270
+ * result = nil
271
+ * keys = ["morita", "gunyara-kun", "yu"]
272
+ * keys.each do |key|
273
+ * result = users.search(key, :result => result)
274
+ * end
275
+ * result.each do |record|
276
+ * user = record.key
277
+ * p user.key # -> "morita"または"gunyara-kun"または"yu"
278
+ * end
279
+ */
280
+ static VALUE
281
+ rb_grn_patricia_trie_search (int argc, VALUE *argv, VALUE self)
282
+ {
283
+ grn_rc rc;
284
+ grn_ctx *context;
285
+ grn_obj *table;
286
+ grn_id domain_id;
287
+ grn_obj *key, *domain, *result;
288
+ grn_operator operator;
289
+ grn_search_optarg search_options;
290
+ rb_grn_boolean search_options_is_set = RB_GRN_FALSE;
291
+ VALUE rb_key, options, rb_result, rb_operator, rb_type;
292
+
293
+ rb_grn_table_key_support_deconstruct(SELF(self), &table, &context,
294
+ &key, &domain_id, &domain,
295
+ NULL, NULL, NULL,
296
+ NULL);
297
+
298
+ rb_scan_args(argc, argv, "11", &rb_key, &options);
299
+
300
+ RVAL2GRNKEY(rb_key, context, key, domain_id, domain, self);
301
+
302
+ rb_grn_scan_options(options,
303
+ "result", &rb_result,
304
+ "operator", &rb_operator,
305
+ "type", &rb_type,
306
+ NULL);
307
+
308
+ if (NIL_P(rb_result)) {
309
+ result = grn_table_create(context, NULL, 0, NULL,
310
+ GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
311
+ table, 0);
312
+ rb_grn_context_check(context, self);
313
+ rb_result = GRNOBJECT2RVAL(Qnil, context, result, RB_GRN_TRUE);
314
+ } else {
315
+ result = RVAL2GRNOBJECT(rb_result, &context);
316
+ }
317
+
318
+ operator = RVAL2GRNOPERATOR(rb_operator);
319
+
320
+ rc = grn_obj_search(context, table, key,
321
+ result, operator,
322
+ search_options_is_set ? &search_options : NULL);
323
+ rb_grn_rc_check(rc, self);
324
+
325
+ return rb_result;
326
+ }
327
+
328
+ /*
329
+ * call-seq:
330
+ * patricia_trie.scan(string) -> Array
331
+ * patricia_trie.scan(string) {|record, word, start, length| ... }
332
+ *
333
+ * _string_を走査し、_patricia_trie_内に格納されているキーに
334
+ * マッチした部分文字列の情報をブロックに渡す。複数のキーが
335
+ * マッチする場合は最長一致するキーを優先する。
336
+ *
337
+ * [_record_]
338
+ * マッチしたキーのGroonga::Record。
339
+ *
340
+ * [_word_]
341
+ * マッチした部分文字列。
342
+ *
343
+ * [_start_]
344
+ * _string_内での_word_の出現位置。(バイト単位)
345
+ *
346
+ * [_length_]
347
+ * _word_の長さ。(バイト探知)
348
+ *
349
+ * ブロックを指定しない場合は、マッチした部分文字列の情報を
350
+ * まとめて配列として返す。
351
+ *
352
+ * words = Groonga::PatriciaTrie.create(:key_type => "ShortText",
353
+ * :key_normalize => true)
354
+ * words.add("リンク")
355
+ * adventure_of_link = words.add('リンクの冒険')
356
+ * words.add('冒険')
357
+ * gaxtu = words.add('ガッ')
358
+ * muteki = words.add('MUTEKI')
359
+ *
360
+ * text = 'muTEki リンクの冒険 ミリバール ガッ'
361
+ * words.scan(text).each do |record, word, start, length|
362
+ * p [record.key, word, start, length]
363
+ * # -> ["MUTEKI", "muTEki", 0, 6]
364
+ * # -> ["リンクの冒険", "リンクの冒険", 7, 18]
365
+ * # -> ["ガッ", "ガッ", 42, 6]
366
+ * end
367
+ *
368
+ * words.scan(text)
369
+ * # -> [[muteki, "muTEki", 0, 6],
370
+ * # [adventure_of_link, "リンクの冒険", 7, 18],
371
+ * # [gaxtu, "ガッ", 42, 6]]
372
+ */
373
+ static VALUE
374
+ rb_grn_patricia_trie_scan (VALUE self, VALUE rb_string)
375
+ {
376
+ grn_ctx *context;
377
+ grn_obj *table;
378
+ VALUE rb_result = Qnil;
379
+ grn_pat_scan_hit hits[1024];
380
+ const char *string;
381
+ long string_length;
382
+ rb_grn_boolean block_given;
383
+
384
+ string = StringValuePtr(rb_string);
385
+ string_length = RSTRING_LEN(rb_string);
386
+
387
+ rb_grn_table_key_support_deconstruct(SELF(self), &table, &context,
388
+ NULL, NULL, NULL,
389
+ NULL, NULL, NULL,
390
+ NULL);
391
+
392
+ block_given = rb_block_given_p();
393
+ if (!block_given)
394
+ rb_result = rb_ary_new();
395
+
396
+ while (string_length > 0) {
397
+ const char *rest;
398
+ int i, n_hits;
399
+ long previous_offset = 0;
400
+
401
+ n_hits = grn_pat_scan(context, (grn_pat *)table,
402
+ string, string_length,
403
+ hits, sizeof(hits) / sizeof(*hits),
404
+ &rest);
405
+ for (i = 0; i < n_hits; i++) {
406
+ VALUE record, term, matched_info;
407
+
408
+ if (hits[i].offset < previous_offset)
409
+ continue;
410
+
411
+ record = rb_grn_record_new(self, hits[i].id, Qnil);
412
+ term = rb_grn_context_rb_string_new(context,
413
+ string + hits[i].offset,
414
+ hits[i].length);
415
+ matched_info = rb_ary_new3(4,
416
+ record,
417
+ term,
418
+ UINT2NUM(hits[i].offset),
419
+ UINT2NUM(hits[i].length));
420
+ if (block_given) {
421
+ rb_yield(matched_info);
422
+ } else {
423
+ rb_ary_push(rb_result, matched_info);
424
+ }
425
+ previous_offset = hits[i].offset;
426
+ }
427
+ string_length -= rest - string;
428
+ string = rest;
429
+ }
430
+
431
+ return rb_result;
432
+ }
433
+
434
+ /*
435
+ * call-seq:
436
+ * patricia_trie.prefix_search(prefix) -> Groonga::Hash
437
+ *
438
+ * キーが_prefix_に前方一致するレコードのIDがキーに入っている
439
+ * Groonga::Hashを返す。マッチするレコードがない場合は空の
440
+ * Groonga::Hashが返る。
441
+ *
442
+ */
443
+ static VALUE
444
+ rb_grn_patricia_trie_prefix_search (VALUE self, VALUE rb_prefix)
445
+ {
446
+ grn_ctx *context;
447
+ grn_obj *table, *key, *domain, *result;
448
+ grn_id domain_id;
449
+ VALUE rb_result;
450
+
451
+ rb_grn_table_key_support_deconstruct(SELF(self), &table, &context,
452
+ &key, &domain_id, &domain,
453
+ NULL, NULL, NULL,
454
+ NULL);
455
+
456
+ result = grn_table_create(context, NULL, 0, NULL,
457
+ GRN_OBJ_TABLE_HASH_KEY,
458
+ table, 0);
459
+ rb_grn_context_check(context, self);
460
+ rb_result = GRNOBJECT2RVAL(Qnil, context, result, RB_GRN_TRUE);
461
+
462
+ GRN_BULK_REWIND(key);
463
+ RVAL2GRNKEY(rb_prefix, context, key, domain_id, domain, self);
464
+ grn_pat_prefix_search(context, (grn_pat *)table,
465
+ GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key),
466
+ (grn_hash *)result);
467
+ rb_grn_context_check(context, self);
468
+
469
+ return rb_result;
470
+ }
471
+
472
+ void
473
+ rb_grn_init_patricia_trie (VALUE mGrn)
474
+ {
475
+ rb_cGrnPatriciaTrie =
476
+ rb_define_class_under(mGrn, "PatriciaTrie", rb_cGrnTable);
477
+
478
+ rb_include_module(rb_cGrnPatriciaTrie, rb_mGrnTableKeySupport);
479
+ rb_define_singleton_method(rb_cGrnPatriciaTrie, "create",
480
+ rb_grn_patricia_trie_s_create, -1);
481
+
482
+ rb_define_method(rb_cGrnPatriciaTrie, "search",
483
+ rb_grn_patricia_trie_search, -1);
484
+ rb_define_method(rb_cGrnPatriciaTrie, "scan",
485
+ rb_grn_patricia_trie_scan, 1);
486
+ rb_define_method(rb_cGrnPatriciaTrie, "prefix_search",
487
+ rb_grn_patricia_trie_prefix_search, 1);
488
+ }