nokogiri 1.10.10 → 1.12.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/LICENSE-DEPENDENCIES.md +1173 -884
  4. data/LICENSE.md +1 -1
  5. data/README.md +176 -96
  6. data/dependencies.yml +12 -12
  7. data/ext/nokogiri/depend +38 -358
  8. data/ext/nokogiri/extconf.rb +716 -414
  9. data/ext/nokogiri/gumbo.c +584 -0
  10. data/ext/nokogiri/html4_document.c +166 -0
  11. data/ext/nokogiri/html4_element_description.c +294 -0
  12. data/ext/nokogiri/html4_entity_lookup.c +37 -0
  13. data/ext/nokogiri/html4_sax_parser_context.c +120 -0
  14. data/ext/nokogiri/html4_sax_push_parser.c +95 -0
  15. data/ext/nokogiri/libxml2_backwards_compat.c +121 -0
  16. data/ext/nokogiri/nokogiri.c +228 -91
  17. data/ext/nokogiri/nokogiri.h +191 -89
  18. data/ext/nokogiri/test_global_handlers.c +40 -0
  19. data/ext/nokogiri/xml_attr.c +15 -15
  20. data/ext/nokogiri/xml_attribute_decl.c +18 -18
  21. data/ext/nokogiri/xml_cdata.c +13 -18
  22. data/ext/nokogiri/xml_comment.c +19 -26
  23. data/ext/nokogiri/xml_document.c +267 -195
  24. data/ext/nokogiri/xml_document_fragment.c +13 -15
  25. data/ext/nokogiri/xml_dtd.c +54 -48
  26. data/ext/nokogiri/xml_element_content.c +31 -26
  27. data/ext/nokogiri/xml_element_decl.c +22 -22
  28. data/ext/nokogiri/xml_encoding_handler.c +28 -17
  29. data/ext/nokogiri/xml_entity_decl.c +32 -30
  30. data/ext/nokogiri/xml_entity_reference.c +16 -18
  31. data/ext/nokogiri/xml_namespace.c +60 -51
  32. data/ext/nokogiri/xml_node.c +493 -407
  33. data/ext/nokogiri/xml_node_set.c +174 -162
  34. data/ext/nokogiri/xml_processing_instruction.c +17 -19
  35. data/ext/nokogiri/xml_reader.c +197 -172
  36. data/ext/nokogiri/xml_relax_ng.c +52 -28
  37. data/ext/nokogiri/xml_sax_parser.c +112 -112
  38. data/ext/nokogiri/xml_sax_parser_context.c +105 -86
  39. data/ext/nokogiri/xml_sax_push_parser.c +36 -27
  40. data/ext/nokogiri/xml_schema.c +96 -46
  41. data/ext/nokogiri/xml_syntax_error.c +42 -21
  42. data/ext/nokogiri/xml_text.c +13 -17
  43. data/ext/nokogiri/xml_xpath_context.c +158 -73
  44. data/ext/nokogiri/xslt_stylesheet.c +158 -164
  45. data/gumbo-parser/CHANGES.md +63 -0
  46. data/gumbo-parser/Makefile +101 -0
  47. data/gumbo-parser/THANKS +27 -0
  48. data/gumbo-parser/src/Makefile +34 -0
  49. data/gumbo-parser/src/README.md +41 -0
  50. data/gumbo-parser/src/ascii.c +75 -0
  51. data/gumbo-parser/src/ascii.h +115 -0
  52. data/gumbo-parser/src/attribute.c +42 -0
  53. data/gumbo-parser/src/attribute.h +17 -0
  54. data/gumbo-parser/src/char_ref.c +22225 -0
  55. data/gumbo-parser/src/char_ref.h +29 -0
  56. data/gumbo-parser/src/char_ref.rl +2154 -0
  57. data/gumbo-parser/src/error.c +626 -0
  58. data/gumbo-parser/src/error.h +148 -0
  59. data/gumbo-parser/src/foreign_attrs.c +104 -0
  60. data/gumbo-parser/src/foreign_attrs.gperf +27 -0
  61. data/gumbo-parser/src/gumbo.h +943 -0
  62. data/gumbo-parser/src/insertion_mode.h +33 -0
  63. data/gumbo-parser/src/macros.h +91 -0
  64. data/gumbo-parser/src/parser.c +4886 -0
  65. data/gumbo-parser/src/parser.h +41 -0
  66. data/gumbo-parser/src/replacement.h +33 -0
  67. data/gumbo-parser/src/string_buffer.c +103 -0
  68. data/gumbo-parser/src/string_buffer.h +68 -0
  69. data/gumbo-parser/src/string_piece.c +48 -0
  70. data/gumbo-parser/src/svg_attrs.c +174 -0
  71. data/gumbo-parser/src/svg_attrs.gperf +77 -0
  72. data/gumbo-parser/src/svg_tags.c +137 -0
  73. data/gumbo-parser/src/svg_tags.gperf +55 -0
  74. data/gumbo-parser/src/tag.c +222 -0
  75. data/gumbo-parser/src/tag_lookup.c +382 -0
  76. data/gumbo-parser/src/tag_lookup.gperf +169 -0
  77. data/gumbo-parser/src/tag_lookup.h +13 -0
  78. data/gumbo-parser/src/token_buffer.c +79 -0
  79. data/gumbo-parser/src/token_buffer.h +71 -0
  80. data/gumbo-parser/src/token_type.h +17 -0
  81. data/gumbo-parser/src/tokenizer.c +3463 -0
  82. data/gumbo-parser/src/tokenizer.h +112 -0
  83. data/gumbo-parser/src/tokenizer_states.h +339 -0
  84. data/gumbo-parser/src/utf8.c +245 -0
  85. data/gumbo-parser/src/utf8.h +164 -0
  86. data/gumbo-parser/src/util.c +68 -0
  87. data/gumbo-parser/src/util.h +30 -0
  88. data/gumbo-parser/src/vector.c +111 -0
  89. data/gumbo-parser/src/vector.h +45 -0
  90. data/lib/nokogiri/css/node.rb +1 -0
  91. data/lib/nokogiri/css/parser.rb +64 -63
  92. data/lib/nokogiri/css/parser.y +3 -3
  93. data/lib/nokogiri/css/parser_extras.rb +39 -36
  94. data/lib/nokogiri/css/syntax_error.rb +2 -1
  95. data/lib/nokogiri/css/tokenizer.rb +1 -0
  96. data/lib/nokogiri/css/xpath_visitor.rb +73 -43
  97. data/lib/nokogiri/css.rb +15 -14
  98. data/lib/nokogiri/decorators/slop.rb +1 -0
  99. data/lib/nokogiri/extension.rb +31 -0
  100. data/lib/nokogiri/gumbo.rb +14 -0
  101. data/lib/nokogiri/html.rb +32 -27
  102. data/lib/nokogiri/{html → html4}/builder.rb +3 -2
  103. data/lib/nokogiri/{html → html4}/document.rb +17 -30
  104. data/lib/nokogiri/{html → html4}/document_fragment.rb +18 -17
  105. data/lib/nokogiri/{html → html4}/element_description.rb +2 -1
  106. data/lib/nokogiri/{html → html4}/element_description_defaults.rb +2 -1
  107. data/lib/nokogiri/{html → html4}/entity_lookup.rb +2 -1
  108. data/lib/nokogiri/{html → html4}/sax/parser.rb +12 -14
  109. data/lib/nokogiri/html4/sax/parser_context.rb +19 -0
  110. data/lib/nokogiri/{html → html4}/sax/push_parser.rb +6 -5
  111. data/lib/nokogiri/html4.rb +40 -0
  112. data/lib/nokogiri/html5/document.rb +74 -0
  113. data/lib/nokogiri/html5/document_fragment.rb +80 -0
  114. data/lib/nokogiri/html5/node.rb +93 -0
  115. data/lib/nokogiri/html5.rb +473 -0
  116. data/lib/nokogiri/jruby/dependencies.rb +20 -0
  117. data/lib/nokogiri/syntax_error.rb +1 -0
  118. data/lib/nokogiri/version/constant.rb +5 -0
  119. data/lib/nokogiri/version/info.rb +215 -0
  120. data/lib/nokogiri/version.rb +3 -109
  121. data/lib/nokogiri/xml/attr.rb +1 -0
  122. data/lib/nokogiri/xml/attribute_decl.rb +1 -0
  123. data/lib/nokogiri/xml/builder.rb +41 -2
  124. data/lib/nokogiri/xml/cdata.rb +1 -0
  125. data/lib/nokogiri/xml/character_data.rb +1 -0
  126. data/lib/nokogiri/xml/document.rb +138 -41
  127. data/lib/nokogiri/xml/document_fragment.rb +5 -6
  128. data/lib/nokogiri/xml/dtd.rb +1 -0
  129. data/lib/nokogiri/xml/element_content.rb +1 -0
  130. data/lib/nokogiri/xml/element_decl.rb +1 -0
  131. data/lib/nokogiri/xml/entity_decl.rb +1 -0
  132. data/lib/nokogiri/xml/entity_reference.rb +1 -0
  133. data/lib/nokogiri/xml/namespace.rb +1 -0
  134. data/lib/nokogiri/xml/node/save_options.rb +2 -1
  135. data/lib/nokogiri/xml/node.rb +629 -293
  136. data/lib/nokogiri/xml/node_set.rb +1 -0
  137. data/lib/nokogiri/xml/notation.rb +1 -0
  138. data/lib/nokogiri/xml/parse_options.rb +12 -3
  139. data/lib/nokogiri/xml/pp/character_data.rb +1 -0
  140. data/lib/nokogiri/xml/pp/node.rb +1 -0
  141. data/lib/nokogiri/xml/pp.rb +3 -2
  142. data/lib/nokogiri/xml/processing_instruction.rb +1 -0
  143. data/lib/nokogiri/xml/reader.rb +9 -12
  144. data/lib/nokogiri/xml/relax_ng.rb +7 -2
  145. data/lib/nokogiri/xml/sax/document.rb +25 -30
  146. data/lib/nokogiri/xml/sax/parser.rb +1 -0
  147. data/lib/nokogiri/xml/sax/parser_context.rb +1 -0
  148. data/lib/nokogiri/xml/sax/push_parser.rb +1 -0
  149. data/lib/nokogiri/xml/sax.rb +5 -4
  150. data/lib/nokogiri/xml/schema.rb +13 -4
  151. data/lib/nokogiri/xml/searchable.rb +25 -16
  152. data/lib/nokogiri/xml/syntax_error.rb +1 -0
  153. data/lib/nokogiri/xml/text.rb +1 -0
  154. data/lib/nokogiri/xml/xpath/syntax_error.rb +2 -1
  155. data/lib/nokogiri/xml/xpath.rb +4 -5
  156. data/lib/nokogiri/xml/xpath_context.rb +1 -0
  157. data/lib/nokogiri/xml.rb +36 -36
  158. data/lib/nokogiri/xslt/stylesheet.rb +2 -1
  159. data/lib/nokogiri/xslt.rb +17 -16
  160. data/lib/nokogiri.rb +32 -51
  161. data/lib/xsd/xmlparser/nokogiri.rb +1 -0
  162. data/patches/libxml2/{0002-Remove-script-macro-support.patch → 0001-Remove-script-macro-support.patch} +0 -0
  163. data/patches/libxml2/{0003-Update-entities-to-remove-handling-of-ssi.patch → 0002-Update-entities-to-remove-handling-of-ssi.patch} +0 -0
  164. data/patches/libxml2/{0004-libxml2.la-is-in-top_builddir.patch → 0003-libxml2.la-is-in-top_builddir.patch} +1 -1
  165. data/patches/libxml2/0004-use-glibc-strlen.patch +53 -0
  166. data/patches/libxml2/0005-avoid-isnan-isinf.patch +81 -0
  167. data/patches/libxml2/0006-update-automake-files-for-arm64.patch +2511 -0
  168. data/patches/libxml2/0007-Fix-XPath-recursion-limit.patch +31 -0
  169. data/patches/libxslt/0001-update-automake-files-for-arm64.patch +2511 -0
  170. data/patches/libxslt/0002-Fix-xml2-config-check-in-configure-script.patch +19 -0
  171. data/ports/archives/libxml2-2.9.12.tar.gz +0 -0
  172. metadata +139 -161
  173. data/ext/nokogiri/html_document.c +0 -170
  174. data/ext/nokogiri/html_document.h +0 -10
  175. data/ext/nokogiri/html_element_description.c +0 -279
  176. data/ext/nokogiri/html_element_description.h +0 -10
  177. data/ext/nokogiri/html_entity_lookup.c +0 -32
  178. data/ext/nokogiri/html_entity_lookup.h +0 -8
  179. data/ext/nokogiri/html_sax_parser_context.c +0 -116
  180. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  181. data/ext/nokogiri/html_sax_push_parser.c +0 -87
  182. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  183. data/ext/nokogiri/xml_attr.h +0 -9
  184. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  185. data/ext/nokogiri/xml_cdata.h +0 -9
  186. data/ext/nokogiri/xml_comment.h +0 -9
  187. data/ext/nokogiri/xml_document.h +0 -23
  188. data/ext/nokogiri/xml_document_fragment.h +0 -10
  189. data/ext/nokogiri/xml_dtd.h +0 -10
  190. data/ext/nokogiri/xml_element_content.h +0 -10
  191. data/ext/nokogiri/xml_element_decl.h +0 -9
  192. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  193. data/ext/nokogiri/xml_entity_decl.h +0 -10
  194. data/ext/nokogiri/xml_entity_reference.h +0 -9
  195. data/ext/nokogiri/xml_io.c +0 -61
  196. data/ext/nokogiri/xml_io.h +0 -11
  197. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  198. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  199. data/ext/nokogiri/xml_namespace.h +0 -14
  200. data/ext/nokogiri/xml_node.h +0 -13
  201. data/ext/nokogiri/xml_node_set.h +0 -12
  202. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  203. data/ext/nokogiri/xml_reader.h +0 -10
  204. data/ext/nokogiri/xml_relax_ng.h +0 -9
  205. data/ext/nokogiri/xml_sax_parser.h +0 -39
  206. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  207. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  208. data/ext/nokogiri/xml_schema.h +0 -9
  209. data/ext/nokogiri/xml_syntax_error.h +0 -13
  210. data/ext/nokogiri/xml_text.h +0 -9
  211. data/ext/nokogiri/xml_xpath_context.h +0 -10
  212. data/ext/nokogiri/xslt_stylesheet.h +0 -14
  213. data/lib/nokogiri/html/sax/parser_context.rb +0 -16
  214. data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
  215. data/patches/libxml2/0005-Fix-infinite-loop-in-xmlStringLenDecodeEntities.patch +0 -32
  216. data/ports/archives/libxml2-2.9.10.tar.gz +0 -0
@@ -1,44 +1,67 @@
1
- #include <xml_document.h>
1
+ #include <nokogiri.h>
2
2
 
3
- static int dealloc_node_i(xmlNodePtr key, xmlNodePtr node, xmlDocPtr doc)
3
+ VALUE cNokogiriXmlDocument ;
4
+
5
+ static int
6
+ dealloc_node_i2(xmlNodePtr key, xmlNodePtr node, xmlDocPtr doc)
4
7
  {
5
- switch(node->type) {
6
- case XML_ATTRIBUTE_NODE:
7
- xmlFreePropList((xmlAttrPtr)node);
8
- break;
9
- case XML_NAMESPACE_DECL:
10
- xmlFreeNs((xmlNsPtr)node);
11
- break;
12
- case XML_DTD_NODE:
13
- xmlFreeDtd((xmlDtdPtr)node);
14
- break;
15
- default:
16
- if(node->parent == NULL) {
17
- xmlAddChild((xmlNodePtr)doc, node);
18
- }
8
+ switch (node->type) {
9
+ case XML_ATTRIBUTE_NODE:
10
+ xmlFreePropList((xmlAttrPtr)node);
11
+ break;
12
+ case XML_NAMESPACE_DECL:
13
+ xmlFreeNs((xmlNsPtr)node);
14
+ break;
15
+ case XML_DTD_NODE:
16
+ xmlFreeDtd((xmlDtdPtr)node);
17
+ break;
18
+ default:
19
+ if (node->parent == NULL) {
20
+ xmlAddChild((xmlNodePtr)doc, node);
21
+ }
19
22
  }
20
23
  return ST_CONTINUE;
21
24
  }
22
25
 
23
- static void remove_private(xmlNodePtr node)
26
+ static int
27
+ dealloc_node_i(st_data_t key, st_data_t node, st_data_t doc)
28
+ {
29
+ return dealloc_node_i2((xmlNodePtr)key, (xmlNodePtr)node, (xmlDocPtr)doc);
30
+ }
31
+
32
+ static void
33
+ remove_private(xmlNodePtr node)
24
34
  {
25
35
  xmlNodePtr child;
26
36
 
27
- for (child = node->children; child; child = child->next)
37
+ for (child = node->children; child; child = child->next) {
28
38
  remove_private(child);
39
+ }
29
40
 
30
41
  if ((node->type == XML_ELEMENT_NODE ||
31
42
  node->type == XML_XINCLUDE_START ||
32
43
  node->type == XML_XINCLUDE_END) &&
33
44
  node->properties) {
34
- for (child = (xmlNodePtr)node->properties; child; child = child->next)
45
+ for (child = (xmlNodePtr)node->properties; child; child = child->next) {
35
46
  remove_private(child);
47
+ }
36
48
  }
37
49
 
38
50
  node->_private = NULL;
39
51
  }
40
52
 
41
- static void dealloc(xmlDocPtr doc)
53
+ static void
54
+ mark(xmlDocPtr doc)
55
+ {
56
+ nokogiriTuplePtr tuple = (nokogiriTuplePtr)doc->_private;
57
+ if (tuple) {
58
+ rb_gc_mark(tuple->doc);
59
+ rb_gc_mark(tuple->node_cache);
60
+ }
61
+ }
62
+
63
+ static void
64
+ dealloc(xmlDocPtr doc)
42
65
  {
43
66
  st_table *node_hash;
44
67
 
@@ -56,23 +79,26 @@ static void dealloc(xmlDocPtr doc)
56
79
  * xmlDeregisterNode callback from accessing VALUE pointers from ruby's GC
57
80
  * free context, which can result in segfaults.
58
81
  */
59
- if (xmlDeregisterNodeDefaultValue)
82
+ if (xmlDeregisterNodeDefaultValue) {
60
83
  remove_private((xmlNodePtr)doc);
84
+ }
61
85
 
62
86
  xmlFreeDoc(doc);
63
87
 
64
88
  NOKOGIRI_DEBUG_END(doc);
65
89
  }
66
90
 
67
- static void recursively_remove_namespaces_from_node(xmlNodePtr node)
91
+ static void
92
+ recursively_remove_namespaces_from_node(xmlNodePtr node)
68
93
  {
69
94
  xmlNodePtr child ;
70
95
  xmlAttrPtr property ;
71
96
 
72
97
  xmlSetNs(node, NULL);
73
98
 
74
- for (child = node->children ; child ; child = child->next)
99
+ for (child = node->children ; child ; child = child->next) {
75
100
  recursively_remove_namespaces_from_node(child);
101
+ }
76
102
 
77
103
  if (((node->type == XML_ELEMENT_NODE) ||
78
104
  (node->type == XML_XINCLUDE_START) ||
@@ -85,7 +111,7 @@ static void recursively_remove_namespaces_from_node(xmlNodePtr node)
85
111
  if (node->type == XML_ELEMENT_NODE && node->properties != NULL) {
86
112
  property = node->properties ;
87
113
  while (property != NULL) {
88
- if (property->ns) property->ns = NULL ;
114
+ if (property->ns) { property->ns = NULL ; }
89
115
  property = property->next ;
90
116
  }
91
117
  }
@@ -97,12 +123,13 @@ static void recursively_remove_namespaces_from_node(xmlNodePtr node)
97
123
  *
98
124
  * Get the url name for this document.
99
125
  */
100
- static VALUE url(VALUE self)
126
+ static VALUE
127
+ url(VALUE self)
101
128
  {
102
129
  xmlDocPtr doc;
103
130
  Data_Get_Struct(self, xmlDoc, doc);
104
131
 
105
- if(doc->URL) return NOKOGIRI_STR_NEW2(doc->URL);
132
+ if (doc->URL) { return NOKOGIRI_STR_NEW2(doc->URL); }
106
133
 
107
134
  return Qnil;
108
135
  }
@@ -113,42 +140,42 @@ static VALUE url(VALUE self)
113
140
  *
114
141
  * Set the root element on this document
115
142
  */
116
- static VALUE set_root(VALUE self, VALUE root)
143
+ static VALUE
144
+ rb_xml_document_root_set(VALUE self, VALUE rb_new_root)
117
145
  {
118
- xmlDocPtr doc;
119
- xmlNodePtr new_root;
120
- xmlNodePtr old_root;
121
-
122
- Data_Get_Struct(self, xmlDoc, doc);
123
-
124
- old_root = NULL;
146
+ xmlDocPtr c_document;
147
+ xmlNodePtr c_new_root = NULL, c_current_root;
125
148
 
126
- if(NIL_P(root)) {
127
- old_root = xmlDocGetRootElement(doc);
128
-
129
- if(old_root) {
130
- xmlUnlinkNode(old_root);
131
- nokogiri_root_node(old_root);
132
- }
149
+ Data_Get_Struct(self, xmlDoc, c_document);
133
150
 
134
- return root;
151
+ c_current_root = xmlDocGetRootElement(c_document);
152
+ if (c_current_root) {
153
+ xmlUnlinkNode(c_current_root);
154
+ noko_xml_document_pin_node(c_current_root);
135
155
  }
136
156
 
137
- Data_Get_Struct(root, xmlNode, new_root);
157
+ if (!NIL_P(rb_new_root)) {
158
+ if (!rb_obj_is_kind_of(rb_new_root, cNokogiriXmlNode)) {
159
+ rb_raise(rb_eArgError,
160
+ "expected Nokogiri::XML::Node but received %"PRIsVALUE,
161
+ rb_obj_class(rb_new_root));
162
+ }
138
163
 
164
+ Data_Get_Struct(rb_new_root, xmlNode, c_new_root);
139
165
 
140
- /* If the new root's document is not the same as the current document,
141
- * then we need to dup the node in to this document. */
142
- if(new_root->doc != doc) {
143
- old_root = xmlDocGetRootElement(doc);
144
- if (!(new_root = xmlDocCopyNode(new_root, doc, 1))) {
145
- rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
166
+ /* If the new root's document is not the same as the current document,
167
+ * then we need to dup the node in to this document. */
168
+ if (c_new_root->doc != c_document) {
169
+ c_new_root = xmlDocCopyNode(c_new_root, c_document, 1);
170
+ if (!c_new_root) {
171
+ rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
172
+ }
146
173
  }
147
174
  }
148
175
 
149
- xmlDocSetRootElement(doc, new_root);
150
- if(old_root) nokogiri_root_node(old_root);
151
- return root;
176
+ xmlDocSetRootElement(c_document, c_new_root);
177
+
178
+ return rb_new_root;
152
179
  }
153
180
 
154
181
  /*
@@ -157,17 +184,20 @@ static VALUE set_root(VALUE self, VALUE root)
157
184
  *
158
185
  * Get the root node for this document.
159
186
  */
160
- static VALUE root(VALUE self)
187
+ static VALUE
188
+ rb_xml_document_root(VALUE self)
161
189
  {
162
- xmlDocPtr doc;
163
- xmlNodePtr root;
190
+ xmlDocPtr c_document;
191
+ xmlNodePtr c_root;
164
192
 
165
- Data_Get_Struct(self, xmlDoc, doc);
193
+ Data_Get_Struct(self, xmlDoc, c_document);
166
194
 
167
- root = xmlDocGetRootElement(doc);
195
+ c_root = xmlDocGetRootElement(c_document);
196
+ if (!c_root) {
197
+ return Qnil;
198
+ }
168
199
 
169
- if(!root) return Qnil;
170
- return Nokogiri_wrap_xml_node(Qnil, root) ;
200
+ return noko_xml_node_wrap(Qnil, c_root) ;
171
201
  }
172
202
 
173
203
  /*
@@ -176,13 +206,15 @@ static VALUE root(VALUE self)
176
206
  *
177
207
  * Set the encoding string for this Document
178
208
  */
179
- static VALUE set_encoding(VALUE self, VALUE encoding)
209
+ static VALUE
210
+ set_encoding(VALUE self, VALUE encoding)
180
211
  {
181
212
  xmlDocPtr doc;
182
213
  Data_Get_Struct(self, xmlDoc, doc);
183
214
 
184
- if (doc->encoding)
185
- free((char *)(uintptr_t) doc->encoding); /* avoid gcc cast warning */
215
+ if (doc->encoding) {
216
+ xmlFree(DISCARD_CONST_QUAL_XMLCHAR(doc->encoding));
217
+ }
186
218
 
187
219
  doc->encoding = xmlStrdup((xmlChar *)StringValueCStr(encoding));
188
220
 
@@ -195,12 +227,13 @@ static VALUE set_encoding(VALUE self, VALUE encoding)
195
227
  *
196
228
  * Get the encoding for this Document
197
229
  */
198
- static VALUE encoding(VALUE self)
230
+ static VALUE
231
+ encoding(VALUE self)
199
232
  {
200
233
  xmlDocPtr doc;
201
234
  Data_Get_Struct(self, xmlDoc, doc);
202
235
 
203
- if(!doc->encoding) return Qnil;
236
+ if (!doc->encoding) { return Qnil; }
204
237
  return NOKOGIRI_STR_NEW2(doc->encoding);
205
238
  }
206
239
 
@@ -210,12 +243,13 @@ static VALUE encoding(VALUE self)
210
243
  *
211
244
  * Get the XML version for this Document
212
245
  */
213
- static VALUE version(VALUE self)
246
+ static VALUE
247
+ version(VALUE self)
214
248
  {
215
249
  xmlDocPtr doc;
216
250
  Data_Get_Struct(self, xmlDoc, doc);
217
251
 
218
- if(!doc->version) return Qnil;
252
+ if (!doc->version) { return Qnil; }
219
253
  return NOKOGIRI_STR_NEW2(doc->version);
220
254
  }
221
255
 
@@ -225,14 +259,15 @@ static VALUE version(VALUE self)
225
259
  *
226
260
  * Create a new document from an IO object
227
261
  */
228
- static VALUE read_io( VALUE klass,
229
- VALUE io,
230
- VALUE url,
231
- VALUE encoding,
232
- VALUE options )
262
+ static VALUE
263
+ read_io(VALUE klass,
264
+ VALUE io,
265
+ VALUE url,
266
+ VALUE encoding,
267
+ VALUE options)
233
268
  {
234
- const char * c_url = NIL_P(url) ? NULL : StringValueCStr(url);
235
- const char * c_enc = NIL_P(encoding) ? NULL : StringValueCStr(encoding);
269
+ const char *c_url = NIL_P(url) ? NULL : StringValueCStr(url);
270
+ const char *c_enc = NIL_P(encoding) ? NULL : StringValueCStr(encoding);
236
271
  VALUE error_list = rb_ary_new();
237
272
  VALUE document;
238
273
  xmlDocPtr doc;
@@ -241,30 +276,31 @@ static VALUE read_io( VALUE klass,
241
276
  xmlSetStructuredErrorFunc((void *)error_list, Nokogiri_error_array_pusher);
242
277
 
243
278
  doc = xmlReadIO(
244
- (xmlInputReadCallback)io_read_callback,
245
- (xmlInputCloseCallback)io_close_callback,
246
- (void *)io,
247
- c_url,
248
- c_enc,
249
- (int)NUM2INT(options)
250
- );
279
+ (xmlInputReadCallback)noko_io_read,
280
+ (xmlInputCloseCallback)noko_io_close,
281
+ (void *)io,
282
+ c_url,
283
+ c_enc,
284
+ (int)NUM2INT(options)
285
+ );
251
286
  xmlSetStructuredErrorFunc(NULL, NULL);
252
287
 
253
- if(doc == NULL) {
288
+ if (doc == NULL) {
254
289
  xmlErrorPtr error;
255
290
 
256
291
  xmlFreeDoc(doc);
257
292
 
258
293
  error = xmlGetLastError();
259
- if(error)
294
+ if (error) {
260
295
  rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
261
- else
296
+ } else {
262
297
  rb_raise(rb_eRuntimeError, "Could not parse document");
298
+ }
263
299
 
264
300
  return Qnil;
265
301
  }
266
302
 
267
- document = Nokogiri_wrap_xml_document(klass, doc);
303
+ document = noko_xml_document_wrap(klass, doc);
268
304
  rb_iv_set(document, "@errors", error_list);
269
305
  return document;
270
306
  }
@@ -275,15 +311,16 @@ static VALUE read_io( VALUE klass,
275
311
  *
276
312
  * Create a new document from a String
277
313
  */
278
- static VALUE read_memory( VALUE klass,
279
- VALUE string,
280
- VALUE url,
281
- VALUE encoding,
282
- VALUE options )
314
+ static VALUE
315
+ read_memory(VALUE klass,
316
+ VALUE string,
317
+ VALUE url,
318
+ VALUE encoding,
319
+ VALUE options)
283
320
  {
284
- const char * c_buffer = StringValuePtr(string);
285
- const char * c_url = NIL_P(url) ? NULL : StringValueCStr(url);
286
- const char * c_enc = NIL_P(encoding) ? NULL : StringValueCStr(encoding);
321
+ const char *c_buffer = StringValuePtr(string);
322
+ const char *c_url = NIL_P(url) ? NULL : StringValueCStr(url);
323
+ const char *c_enc = NIL_P(encoding) ? NULL : StringValueCStr(encoding);
287
324
  int len = (int)RSTRING_LEN(string);
288
325
  VALUE error_list = rb_ary_new();
289
326
  VALUE document;
@@ -294,21 +331,22 @@ static VALUE read_memory( VALUE klass,
294
331
  doc = xmlReadMemory(c_buffer, len, c_url, c_enc, (int)NUM2INT(options));
295
332
  xmlSetStructuredErrorFunc(NULL, NULL);
296
333
 
297
- if(doc == NULL) {
334
+ if (doc == NULL) {
298
335
  xmlErrorPtr error;
299
336
 
300
337
  xmlFreeDoc(doc);
301
338
 
302
339
  error = xmlGetLastError();
303
- if(error)
340
+ if (error) {
304
341
  rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
305
- else
342
+ } else {
306
343
  rb_raise(rb_eRuntimeError, "Could not parse document");
344
+ }
307
345
 
308
346
  return Qnil;
309
347
  }
310
348
 
311
- document = Nokogiri_wrap_xml_document(klass, doc);
349
+ document = noko_xml_document_wrap(klass, doc);
312
350
  rb_iv_set(document, "@errors", error_list);
313
351
  return document;
314
352
  }
@@ -320,26 +358,26 @@ static VALUE read_memory( VALUE klass,
320
358
  * Copy this Document. An optional depth may be passed in, but it defaults
321
359
  * to a deep copy. 0 is a shallow copy, 1 is a deep copy.
322
360
  */
323
- static VALUE duplicate_document(int argc, VALUE *argv, VALUE self)
361
+ static VALUE
362
+ duplicate_document(int argc, VALUE *argv, VALUE self)
324
363
  {
325
364
  xmlDocPtr doc, dup;
326
365
  VALUE copy;
327
366
  VALUE level;
328
- VALUE error_list;
329
367
 
330
- if(rb_scan_args(argc, argv, "01", &level) == 0)
368
+ if (rb_scan_args(argc, argv, "01", &level) == 0) {
331
369
  level = INT2NUM((long)1);
370
+ }
332
371
 
333
372
  Data_Get_Struct(self, xmlDoc, doc);
334
373
 
335
374
  dup = xmlCopyDoc(doc, (int)NUM2INT(level));
336
375
 
337
- if(dup == NULL) return Qnil;
376
+ if (dup == NULL) { return Qnil; }
338
377
 
339
378
  dup->type = doc->type;
340
- copy = Nokogiri_wrap_xml_document(rb_obj_class(self), dup);
341
- error_list = rb_iv_get(self, "@errors");
342
- rb_iv_set(copy, "@errors", error_list);
379
+ copy = noko_xml_document_wrap(rb_obj_class(self), dup);
380
+ rb_iv_set(copy, "@errors", rb_iv_get(self, "@errors"));
343
381
  return copy ;
344
382
  }
345
383
 
@@ -349,18 +387,18 @@ static VALUE duplicate_document(int argc, VALUE *argv, VALUE self)
349
387
  *
350
388
  * Create a new document with +version+ (defaults to "1.0")
351
389
  */
352
- static VALUE new(int argc, VALUE *argv, VALUE klass)
390
+ static VALUE
391
+ new (int argc, VALUE *argv, VALUE klass)
353
392
  {
354
393
  xmlDocPtr doc;
355
394
  VALUE version, rest, rb_doc ;
356
395
 
357
396
  rb_scan_args(argc, argv, "0*", &rest);
358
397
  version = rb_ary_entry(rest, (long)0);
359
- if (NIL_P(version)) version = rb_str_new2("1.0");
398
+ if (NIL_P(version)) { version = rb_str_new2("1.0"); }
360
399
 
361
400
  doc = xmlNewDoc((xmlChar *)StringValueCStr(version));
362
- rb_doc = Nokogiri_wrap_xml_document(klass, doc);
363
- rb_obj_call_init(rb_doc, argc, argv);
401
+ rb_doc = noko_xml_document_wrap_with_init_args(klass, doc, argc, argv);
364
402
  return rb_doc ;
365
403
  }
366
404
 
@@ -401,7 +439,8 @@ static VALUE new(int argc, VALUE *argv, VALUE klass)
401
439
  * please direct your browser to
402
440
  * http://tenderlovemaking.com/2009/04/23/namespaces-in-xml.html
403
441
  */
404
- VALUE remove_namespaces_bang(VALUE self)
442
+ static VALUE
443
+ remove_namespaces_bang(VALUE self)
405
444
  {
406
445
  xmlDocPtr doc ;
407
446
  Data_Get_Struct(self, xmlDoc, doc);
@@ -421,7 +460,8 @@ VALUE remove_namespaces_bang(VALUE self)
421
460
  * +external_id+, +system_id+, and +content+ set the External ID, System ID,
422
461
  * and content respectively. All of these parameters are optional.
423
462
  */
424
- static VALUE create_entity(int argc, VALUE *argv, VALUE self)
463
+ static VALUE
464
+ create_entity(int argc, VALUE *argv, VALUE self)
425
465
  {
426
466
  VALUE name;
427
467
  VALUE type;
@@ -434,52 +474,50 @@ static VALUE create_entity(int argc, VALUE *argv, VALUE self)
434
474
  Data_Get_Struct(self, xmlDoc, doc);
435
475
 
436
476
  rb_scan_args(argc, argv, "14", &name, &type, &external_id, &system_id,
437
- &content);
477
+ &content);
438
478
 
439
479
  xmlResetLastError();
440
480
  ptr = xmlAddDocEntity(
441
- doc,
442
- (xmlChar *)(NIL_P(name) ? NULL : StringValueCStr(name)),
443
- (int) (NIL_P(type) ? XML_INTERNAL_GENERAL_ENTITY : NUM2INT(type)),
444
- (xmlChar *)(NIL_P(external_id) ? NULL : StringValueCStr(external_id)),
445
- (xmlChar *)(NIL_P(system_id) ? NULL : StringValueCStr(system_id)),
446
- (xmlChar *)(NIL_P(content) ? NULL : StringValueCStr(content))
447
- );
448
-
449
- if(NULL == ptr) {
481
+ doc,
482
+ (xmlChar *)(NIL_P(name) ? NULL : StringValueCStr(name)),
483
+ (int)(NIL_P(type) ? XML_INTERNAL_GENERAL_ENTITY : NUM2INT(type)),
484
+ (xmlChar *)(NIL_P(external_id) ? NULL : StringValueCStr(external_id)),
485
+ (xmlChar *)(NIL_P(system_id) ? NULL : StringValueCStr(system_id)),
486
+ (xmlChar *)(NIL_P(content) ? NULL : StringValueCStr(content))
487
+ );
488
+
489
+ if (NULL == ptr) {
450
490
  xmlErrorPtr error = xmlGetLastError();
451
- if(error)
491
+ if (error) {
452
492
  rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
453
- else
493
+ } else {
454
494
  rb_raise(rb_eRuntimeError, "Could not create entity");
495
+ }
455
496
 
456
497
  return Qnil;
457
498
  }
458
499
 
459
- return Nokogiri_wrap_xml_node(cNokogiriXmlEntityDecl, (xmlNodePtr)ptr);
500
+ return noko_xml_node_wrap(cNokogiriXmlEntityDecl, (xmlNodePtr)ptr);
460
501
  }
461
502
 
462
- static int block_caller(void * ctx, xmlNodePtr _node, xmlNodePtr _parent)
503
+ static int
504
+ block_caller(void *ctx, xmlNodePtr c_node, xmlNodePtr c_parent_node)
463
505
  {
464
- VALUE block;
465
- VALUE node;
466
- VALUE parent;
506
+ VALUE block = (VALUE)ctx;
507
+ VALUE rb_node;
508
+ VALUE rb_parent_node;
467
509
  VALUE ret;
468
510
 
469
- if(_node->type == XML_NAMESPACE_DECL){
470
- node = Nokogiri_wrap_xml_namespace(_parent->doc, (xmlNsPtr) _node);
471
- }
472
- else{
473
- node = Nokogiri_wrap_xml_node(Qnil, _node);
511
+ if (c_node->type == XML_NAMESPACE_DECL) {
512
+ rb_node = noko_xml_namespace_wrap((xmlNsPtr)c_node, c_parent_node->doc);
513
+ } else {
514
+ rb_node = noko_xml_node_wrap(Qnil, c_node);
474
515
  }
475
- parent = _parent ? Nokogiri_wrap_xml_node(Qnil, _parent) : Qnil;
476
- block = (VALUE)ctx;
516
+ rb_parent_node = c_parent_node ? noko_xml_node_wrap(Qnil, c_parent_node) : Qnil;
477
517
 
478
- ret = rb_funcall(block, rb_intern("call"), 2, node, parent);
518
+ ret = rb_funcall(block, rb_intern("call"), 2, rb_node, rb_parent_node);
479
519
 
480
- if(Qfalse == ret || Qnil == ret) return 0;
481
-
482
- return 1;
520
+ return (Qfalse == ret || Qnil == ret) ? 0 : 1;
483
521
  }
484
522
 
485
523
  /* call-seq:
@@ -492,7 +530,8 @@ static int block_caller(void * ctx, xmlNodePtr _node, xmlNodePtr _parent)
492
530
  * The block must return a non-nil, non-false value if the +obj+ passed in
493
531
  * should be included in the canonicalized document.
494
532
  */
495
- static VALUE canonicalize(int argc, VALUE* argv, VALUE self)
533
+ static VALUE
534
+ rb_xml_document_canonicalize(int argc, VALUE *argv, VALUE self)
496
535
  {
497
536
  VALUE mode;
498
537
  VALUE incl_ns;
@@ -503,7 +542,7 @@ static VALUE canonicalize(int argc, VALUE* argv, VALUE self)
503
542
  xmlDocPtr doc;
504
543
  xmlOutputBufferPtr buf;
505
544
  xmlC14NIsVisibleCallback cb = NULL;
506
- void * ctx = NULL;
545
+ void *ctx = NULL;
507
546
 
508
547
  VALUE rb_cStringIO;
509
548
  VALUE io;
@@ -516,93 +555,126 @@ static VALUE canonicalize(int argc, VALUE* argv, VALUE self)
516
555
  io = rb_class_new_instance(0, 0, rb_cStringIO);
517
556
  buf = xmlAllocOutputBuffer(NULL);
518
557
 
519
- buf->writecallback = (xmlOutputWriteCallback)io_write_callback;
520
- buf->closecallback = (xmlOutputCloseCallback)io_close_callback;
558
+ buf->writecallback = (xmlOutputWriteCallback)noko_io_write;
559
+ buf->closecallback = (xmlOutputCloseCallback)noko_io_close;
521
560
  buf->context = (void *)io;
522
561
 
523
- if(rb_block_given_p()) {
562
+ if (rb_block_given_p()) {
524
563
  cb = block_caller;
525
564
  ctx = (void *)rb_block_proc();
526
565
  }
527
566
 
528
- if(NIL_P(incl_ns)){
567
+ if (NIL_P(incl_ns)) {
529
568
  ns = NULL;
530
- }
531
- else{
569
+ } else {
532
570
  Check_Type(incl_ns, T_ARRAY);
533
571
  ns_len = RARRAY_LEN(incl_ns);
534
- ns = calloc((size_t)ns_len+1, sizeof(xmlChar *));
572
+ ns = calloc((size_t)ns_len + 1, sizeof(xmlChar *));
535
573
  for (i = 0 ; i < ns_len ; i++) {
536
574
  VALUE entry = rb_ary_entry(incl_ns, i);
537
- ns[i] = (xmlChar*)StringValueCStr(entry);
575
+ ns[i] = (xmlChar *)StringValueCStr(entry);
538
576
  }
539
577
  }
540
578
 
541
579
 
542
580
  xmlC14NExecute(doc, cb, ctx,
543
- (int) (NIL_P(mode) ? 0 : NUM2INT(mode)),
544
- ns,
545
- (int) RTEST(with_comments),
546
- buf);
581
+ (int)(NIL_P(mode) ? 0 : NUM2INT(mode)),
582
+ ns,
583
+ (int) RTEST(with_comments),
584
+ buf);
547
585
 
548
586
  xmlOutputBufferClose(buf);
549
587
 
550
588
  return rb_funcall(io, rb_intern("string"), 0);
551
589
  }
552
590
 
553
- VALUE cNokogiriXmlDocument ;
554
- void init_xml_document()
591
+ VALUE
592
+ noko_xml_document_wrap_with_init_args(VALUE klass, xmlDocPtr c_document, int argc, VALUE *argv)
555
593
  {
556
- VALUE nokogiri = rb_define_module("Nokogiri");
557
- VALUE xml = rb_define_module_under(nokogiri, "XML");
558
- VALUE node = rb_define_class_under(xml, "Node", rb_cObject);
594
+ VALUE rb_document;
595
+ nokogiriTuplePtr tuple;
559
596
 
560
- /*
561
- * Nokogiri::XML::Document wraps an xml document.
562
- */
563
- VALUE klass = rb_define_class_under(xml, "Document", node);
564
-
565
- cNokogiriXmlDocument = klass;
566
-
567
- rb_define_singleton_method(klass, "read_memory", read_memory, 4);
568
- rb_define_singleton_method(klass, "read_io", read_io, 4);
569
- rb_define_singleton_method(klass, "new", new, -1);
570
-
571
- rb_define_method(klass, "root", root, 0);
572
- rb_define_method(klass, "root=", set_root, 1);
573
- rb_define_method(klass, "encoding", encoding, 0);
574
- rb_define_method(klass, "encoding=", set_encoding, 1);
575
- rb_define_method(klass, "version", version, 0);
576
- rb_define_method(klass, "canonicalize", canonicalize, -1);
577
- rb_define_method(klass, "dup", duplicate_document, -1);
578
- rb_define_method(klass, "url", url, 0);
579
- rb_define_method(klass, "create_entity", create_entity, -1);
580
- rb_define_method(klass, "remove_namespaces!", remove_namespaces_bang, 0);
597
+ if (!klass) {
598
+ klass = cNokogiriXmlDocument;
599
+ }
600
+
601
+ rb_document = Data_Wrap_Struct(klass, mark, dealloc, c_document);
602
+
603
+ tuple = (nokogiriTuplePtr)malloc(sizeof(nokogiriTuple));
604
+ tuple->doc = rb_document;
605
+ tuple->unlinkedNodes = st_init_numtable_with_size(128);
606
+ tuple->node_cache = rb_ary_new();
607
+
608
+ c_document->_private = tuple ;
609
+
610
+ rb_iv_set(rb_document, "@decorators", Qnil);
611
+ rb_iv_set(rb_document, "@errors", Qnil);
612
+ rb_iv_set(rb_document, "@node_cache", tuple->node_cache);
613
+
614
+ rb_obj_call_init(rb_document, argc, argv);
615
+
616
+ return rb_document ;
617
+ }
618
+
619
+
620
+ /* deprecated. use noko_xml_document_wrap() instead. */
621
+ VALUE
622
+ Nokogiri_wrap_xml_document(VALUE klass, xmlDocPtr doc)
623
+ {
624
+ /* TODO: deprecate this method in v2.0 */
625
+ return noko_xml_document_wrap_with_init_args(klass, doc, 0, NULL);
626
+ }
627
+
628
+ VALUE
629
+ noko_xml_document_wrap(VALUE klass, xmlDocPtr doc)
630
+ {
631
+ return noko_xml_document_wrap_with_init_args(klass, doc, 0, NULL);
581
632
  }
582
633
 
583
634
 
584
- /* this takes klass as a param because it's used for HtmlDocument, too. */
585
- VALUE Nokogiri_wrap_xml_document(VALUE klass, xmlDocPtr doc)
635
+ void
636
+ noko_xml_document_pin_node(xmlNodePtr node)
586
637
  {
587
- nokogiriTuplePtr tuple = (nokogiriTuplePtr)malloc(sizeof(nokogiriTuple));
638
+ xmlDocPtr doc;
639
+ nokogiriTuplePtr tuple;
588
640
 
589
- VALUE rb_doc = Data_Wrap_Struct(
590
- klass ? klass : cNokogiriXmlDocument,
591
- 0,
592
- dealloc,
593
- doc
594
- );
641
+ doc = node->doc;
642
+ tuple = (nokogiriTuplePtr)doc->_private;
643
+ st_insert(tuple->unlinkedNodes, (st_data_t)node, (st_data_t)node);
644
+ }
595
645
 
596
- VALUE cache = rb_ary_new();
597
- rb_iv_set(rb_doc, "@decorators", Qnil);
598
- rb_iv_set(rb_doc, "@node_cache", cache);
599
646
 
600
- tuple->doc = rb_doc;
601
- tuple->unlinkedNodes = st_init_numtable_with_size(128);
602
- tuple->node_cache = cache;
603
- doc->_private = tuple ;
647
+ void
648
+ noko_xml_document_pin_namespace(xmlNsPtr ns, xmlDocPtr doc)
649
+ {
650
+ nokogiriTuplePtr tuple;
651
+
652
+ tuple = (nokogiriTuplePtr)doc->_private;
653
+ st_insert(tuple->unlinkedNodes, (st_data_t)ns, (st_data_t)ns);
654
+ }
604
655
 
605
- rb_obj_call_init(rb_doc, 0, NULL);
606
656
 
607
- return rb_doc ;
657
+ void
658
+ noko_init_xml_document()
659
+ {
660
+ assert(cNokogiriXmlNode);
661
+ /*
662
+ * Nokogiri::XML::Document wraps an xml document.
663
+ */
664
+ cNokogiriXmlDocument = rb_define_class_under(mNokogiriXml, "Document", cNokogiriXmlNode);
665
+
666
+ rb_define_singleton_method(cNokogiriXmlDocument, "read_memory", read_memory, 4);
667
+ rb_define_singleton_method(cNokogiriXmlDocument, "read_io", read_io, 4);
668
+ rb_define_singleton_method(cNokogiriXmlDocument, "new", new, -1);
669
+
670
+ rb_define_method(cNokogiriXmlDocument, "root", rb_xml_document_root, 0);
671
+ rb_define_method(cNokogiriXmlDocument, "root=", rb_xml_document_root_set, 1);
672
+ rb_define_method(cNokogiriXmlDocument, "encoding", encoding, 0);
673
+ rb_define_method(cNokogiriXmlDocument, "encoding=", set_encoding, 1);
674
+ rb_define_method(cNokogiriXmlDocument, "version", version, 0);
675
+ rb_define_method(cNokogiriXmlDocument, "canonicalize", rb_xml_document_canonicalize, -1);
676
+ rb_define_method(cNokogiriXmlDocument, "dup", duplicate_document, -1);
677
+ rb_define_method(cNokogiriXmlDocument, "url", url, 0);
678
+ rb_define_method(cNokogiriXmlDocument, "create_entity", create_entity, -1);
679
+ rb_define_method(cNokogiriXmlDocument, "remove_namespaces!", remove_namespaces_bang, 0);
608
680
  }