Lines 19-34
Link Here
|
19 |
|
19 |
|
20 |
import java.io.OutputStream; |
20 |
import java.io.OutputStream; |
21 |
|
21 |
|
22 |
import org.dom4j.Document; |
|
|
23 |
import org.dom4j.DocumentHelper; |
24 |
import org.dom4j.Element; |
25 |
import org.dom4j.Namespace; |
26 |
import org.dom4j.QName; |
27 |
import org.apache.poi.openxml4j.exceptions.OpenXML4JException; |
22 |
import org.apache.poi.openxml4j.exceptions.OpenXML4JException; |
28 |
import org.apache.poi.openxml4j.opc.PackagePart; |
23 |
import org.apache.poi.openxml4j.opc.PackagePart; |
29 |
import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; |
24 |
import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; |
30 |
import org.apache.poi.openxml4j.opc.internal.PartMarshaller; |
25 |
import org.apache.poi.openxml4j.opc.internal.PartMarshaller; |
|
|
26 |
import org.apache.poi.openxml4j.util.Nullable; |
27 |
import org.apache.poi.util.DocumentHelper; |
28 |
import org.apache.poi.util.XMLHelper; |
29 |
import org.w3c.dom.Document; |
30 |
import org.w3c.dom.Element; |
31 |
|
31 |
|
|
|
32 |
import javax.xml.XMLConstants; |
33 |
import javax.xml.stream.XMLEventFactory; |
34 |
import javax.xml.stream.events.Namespace; |
35 |
|
32 |
/** |
36 |
/** |
33 |
* Package properties marshaller. |
37 |
* Package properties marshaller. |
34 |
* |
38 |
* |
Lines 36-52
Link Here
|
36 |
*/ |
40 |
*/ |
37 |
public class PackagePropertiesMarshaller implements PartMarshaller { |
41 |
public class PackagePropertiesMarshaller implements PartMarshaller { |
38 |
|
42 |
|
39 |
private final static Namespace namespaceDC = new Namespace("dc", |
43 |
private final static Namespace namespaceDC = XMLEventFactory.newFactory().createNamespace("dc", |
40 |
PackagePropertiesPart.NAMESPACE_DC_URI); |
44 |
PackagePropertiesPart.NAMESPACE_DC_URI); |
41 |
|
45 |
|
42 |
private final static Namespace namespaceCoreProperties = new Namespace("", |
46 |
private final static Namespace namespaceCoreProperties = XMLEventFactory.newFactory().createNamespace("", |
43 |
PackagePropertiesPart.NAMESPACE_CP_URI); |
47 |
PackagePropertiesPart.NAMESPACE_CP_URI); |
44 |
|
48 |
|
45 |
private final static Namespace namespaceDcTerms = new Namespace("dcterms", |
49 |
private final static Namespace namespaceDcTerms = XMLEventFactory.newFactory().createNamespace("dcterms", |
46 |
PackagePropertiesPart.NAMESPACE_DCTERMS_URI); |
50 |
PackagePropertiesPart.NAMESPACE_DCTERMS_URI); |
47 |
|
51 |
|
48 |
private final static Namespace namespaceXSI = new Namespace("xsi", |
52 |
private final static Namespace namespaceXSI = XMLEventFactory.newFactory().createNamespace("xsi", |
49 |
PackagePropertiesPart.NAMESPACE_XSI_URI); |
53 |
XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); |
50 |
|
54 |
|
51 |
protected static final String KEYWORD_CATEGORY = "category"; |
55 |
protected static final String KEYWORD_CATEGORY = "category"; |
52 |
|
56 |
|
Lines 98-110
Link Here
|
98 |
|
102 |
|
99 |
// Configure the document |
103 |
// Configure the document |
100 |
xmlDoc = DocumentHelper.createDocument(); |
104 |
xmlDoc = DocumentHelper.createDocument(); |
101 |
Element rootElem = xmlDoc.addElement(new QName("coreProperties", |
105 |
Element rootElem = xmlDoc.createElementNS(namespaceCoreProperties.getNamespaceURI(), "coreProperties"); |
102 |
namespaceCoreProperties)); |
106 |
XMLHelper.addNamespaceDeclaration(rootElem, "cp", PackagePropertiesPart.NAMESPACE_CP_URI); |
103 |
rootElem.addNamespace("cp", PackagePropertiesPart.NAMESPACE_CP_URI); |
107 |
XMLHelper.addNamespaceDeclaration(rootElem, "dc", PackagePropertiesPart.NAMESPACE_DC_URI); |
104 |
rootElem.addNamespace("dc", PackagePropertiesPart.NAMESPACE_DC_URI); |
108 |
XMLHelper.addNamespaceDeclaration(rootElem, "dcterms", PackagePropertiesPart.NAMESPACE_DCTERMS_URI); |
105 |
rootElem.addNamespace("dcterms", |
109 |
XMLHelper.addNamespaceDeclaration(rootElem, "xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); |
106 |
PackagePropertiesPart.NAMESPACE_DCTERMS_URI); |
110 |
xmlDoc.appendChild(rootElem); |
107 |
rootElem.addNamespace("xsi", PackagePropertiesPart.NAMESPACE_XSI_URI); |
|
|
108 |
|
111 |
|
109 |
addCategory(); |
112 |
addCategory(); |
110 |
addContentStatus(); |
113 |
addContentStatus(); |
Lines 125-433
Link Here
|
125 |
return true; |
128 |
return true; |
126 |
} |
129 |
} |
127 |
|
130 |
|
128 |
/** |
131 |
/** |
129 |
* Add category property element if needed. |
132 |
* Sets the given element's text content, creating it if necessary. |
130 |
*/ |
133 |
*/ |
131 |
private void addCategory() { |
134 |
private Element setElementTextContent(String localName, Namespace namespace, Nullable<String> property) { |
132 |
if (!propsPart.getCategoryProperty().hasValue()) |
135 |
return setElementTextContent(localName, namespace, property, property.getValue()); |
133 |
return; |
136 |
} |
134 |
|
137 |
|
135 |
Element elem = xmlDoc.getRootElement().element( |
138 |
private Element setElementTextContent(String localName, Namespace namespace, Nullable<?> property, String propertyValue) { |
136 |
new QName(KEYWORD_CATEGORY, namespaceCoreProperties)); |
139 |
if (!property.hasValue()) |
|
|
140 |
return null; |
141 |
|
142 |
Element root = xmlDoc.getDocumentElement(); |
143 |
Element elem = (Element) root.getElementsByTagNameNS(namespace.getNamespaceURI(), localName).item(0); |
137 |
if (elem == null) { |
144 |
if (elem == null) { |
138 |
// Missing, we add it |
145 |
// missing, we add it |
139 |
elem = xmlDoc.getRootElement().addElement( |
146 |
String qualifiedName = namespace.getPrefix().isEmpty() ? localName : namespace.getPrefix() + ':' + localName; |
140 |
new QName(KEYWORD_CATEGORY, namespaceCoreProperties)); |
147 |
elem = xmlDoc.createElementNS(namespace.getNamespaceURI(), qualifiedName); |
141 |
} else { |
148 |
root.appendChild(elem); |
142 |
elem.clearContent();// clear the old value |
|
|
143 |
} |
149 |
} |
144 |
elem.addText(propsPart.getCategoryProperty().getValue()); |
150 |
elem.setTextContent(propertyValue); |
|
|
151 |
return elem; |
145 |
} |
152 |
} |
146 |
|
153 |
|
147 |
/** |
154 |
private Element setElementTextContent(String localName, Namespace namespace, Nullable<?> property, String propertyValue, String xsiType) { |
|
|
155 |
Element element = setElementTextContent(localName, namespace, property, propertyValue); |
156 |
if (element != null) { |
157 |
element.setAttributeNS(namespaceXSI.getNamespaceURI(), namespaceXSI.getPrefix() + ':' + "type", xsiType); |
158 |
} |
159 |
return element; |
160 |
} |
161 |
|
162 |
|
|
|
163 |
/** |
164 |
* Add category property element if needed. |
165 |
*/ |
166 |
private void addCategory() { |
167 |
setElementTextContent(KEYWORD_CATEGORY, namespaceCoreProperties, propsPart.getCategoryProperty()); |
168 |
} |
169 |
|
170 |
/** |
148 |
* Add content status property element if needed. |
171 |
* Add content status property element if needed. |
149 |
*/ |
172 |
*/ |
150 |
private void addContentStatus() { |
173 |
private void addContentStatus() { |
151 |
if (!propsPart.getContentStatusProperty().hasValue()) |
174 |
setElementTextContent(KEYWORD_CONTENT_STATUS, namespaceCoreProperties, propsPart.getContentStatusProperty()); |
152 |
return; |
|
|
153 |
|
154 |
Element elem = xmlDoc.getRootElement().element( |
155 |
new QName(KEYWORD_CONTENT_STATUS, namespaceCoreProperties)); |
156 |
if (elem == null) { |
157 |
// Missing, we add it |
158 |
elem = xmlDoc.getRootElement().addElement( |
159 |
new QName(KEYWORD_CONTENT_STATUS, namespaceCoreProperties)); |
160 |
} else { |
161 |
elem.clearContent();// clear the old value |
162 |
} |
175 |
} |
163 |
elem.addText(propsPart.getContentStatusProperty().getValue()); |
|
|
164 |
} |
165 |
|
176 |
|
166 |
/** |
177 |
/** |
167 |
* Add content type property element if needed. |
178 |
* Add content type property element if needed. |
168 |
*/ |
179 |
*/ |
169 |
private void addContentType() { |
180 |
private void addContentType() { |
170 |
if (!propsPart.getContentTypeProperty().hasValue()) |
181 |
setElementTextContent(KEYWORD_CONTENT_TYPE, namespaceCoreProperties, propsPart.getContentTypeProperty()); |
171 |
return; |
|
|
172 |
|
173 |
Element elem = xmlDoc.getRootElement().element( |
174 |
new QName(KEYWORD_CONTENT_TYPE, namespaceCoreProperties)); |
175 |
if (elem == null) { |
176 |
// Missing, we add it |
177 |
elem = xmlDoc.getRootElement().addElement( |
178 |
new QName(KEYWORD_CONTENT_TYPE, namespaceCoreProperties)); |
179 |
} else { |
180 |
elem.clearContent();// clear the old value |
181 |
} |
182 |
} |
182 |
elem.addText(propsPart.getContentTypeProperty().getValue()); |
|
|
183 |
} |
184 |
|
183 |
|
185 |
/** |
184 |
/** |
186 |
* Add created property element if needed. |
185 |
* Add created property element if needed. |
187 |
*/ |
186 |
*/ |
188 |
private void addCreated() { |
187 |
private void addCreated() { |
189 |
if (!propsPart.getCreatedProperty().hasValue()) |
188 |
setElementTextContent(KEYWORD_CREATED, namespaceDcTerms, propsPart.getCreatedProperty(), |
190 |
return; |
189 |
propsPart.getCreatedPropertyString(), "dcterms:W3CDTF"); |
191 |
|
|
|
192 |
Element elem = xmlDoc.getRootElement().element( |
193 |
new QName(KEYWORD_CREATED, namespaceDcTerms)); |
194 |
if (elem == null) { |
195 |
// missing, we add it |
196 |
elem = xmlDoc.getRootElement().addElement( |
197 |
new QName(KEYWORD_CREATED, namespaceDcTerms)); |
198 |
} else { |
199 |
elem.clearContent();// clear the old value |
200 |
} |
190 |
} |
201 |
elem.addAttribute(new QName("type", namespaceXSI), "dcterms:W3CDTF"); |
|
|
202 |
elem.addText(propsPart.getCreatedPropertyString()); |
203 |
} |
204 |
|
191 |
|
205 |
/** |
192 |
/** |
206 |
* Add creator property element if needed. |
193 |
* Add creator property element if needed. |
207 |
*/ |
194 |
*/ |
208 |
private void addCreator() { |
195 |
private void addCreator() { |
209 |
if (!propsPart.getCreatorProperty().hasValue()) |
196 |
setElementTextContent(KEYWORD_CREATOR, namespaceDC, propsPart.getCreatorProperty()); |
210 |
return; |
|
|
211 |
|
212 |
Element elem = xmlDoc.getRootElement().element( |
213 |
new QName(KEYWORD_CREATOR, namespaceDC)); |
214 |
if (elem == null) { |
215 |
// missing, we add it |
216 |
elem = xmlDoc.getRootElement().addElement( |
217 |
new QName(KEYWORD_CREATOR, namespaceDC)); |
218 |
} else { |
219 |
elem.clearContent();// clear the old value |
220 |
} |
197 |
} |
221 |
elem.addText(propsPart.getCreatorProperty().getValue()); |
|
|
222 |
} |
223 |
|
198 |
|
224 |
/** |
199 |
/** |
225 |
* Add description property element if needed. |
200 |
* Add description property element if needed. |
226 |
*/ |
201 |
*/ |
227 |
private void addDescription() { |
202 |
private void addDescription() { |
228 |
if (!propsPart.getDescriptionProperty().hasValue()) |
203 |
setElementTextContent(KEYWORD_DESCRIPTION, namespaceDC, propsPart.getDescriptionProperty()); |
229 |
return; |
|
|
230 |
|
231 |
Element elem = xmlDoc.getRootElement().element( |
232 |
new QName(KEYWORD_DESCRIPTION, namespaceDC)); |
233 |
if (elem == null) { |
234 |
// missing, we add it |
235 |
elem = xmlDoc.getRootElement().addElement( |
236 |
new QName(KEYWORD_DESCRIPTION, namespaceDC)); |
237 |
} else { |
238 |
elem.clearContent();// clear the old value |
239 |
} |
204 |
} |
240 |
elem.addText(propsPart.getDescriptionProperty().getValue()); |
|
|
241 |
} |
242 |
|
205 |
|
243 |
/** |
206 |
/** |
244 |
* Add identifier property element if needed. |
207 |
* Add identifier property element if needed. |
245 |
*/ |
208 |
*/ |
246 |
private void addIdentifier() { |
209 |
private void addIdentifier() { |
247 |
if (!propsPart.getIdentifierProperty().hasValue()) |
210 |
setElementTextContent(KEYWORD_IDENTIFIER, namespaceDC, propsPart.getIdentifierProperty()); |
248 |
return; |
|
|
249 |
|
250 |
Element elem = xmlDoc.getRootElement().element( |
251 |
new QName(KEYWORD_IDENTIFIER, namespaceDC)); |
252 |
if (elem == null) { |
253 |
// missing, we add it |
254 |
elem = xmlDoc.getRootElement().addElement( |
255 |
new QName(KEYWORD_IDENTIFIER, namespaceDC)); |
256 |
} else { |
257 |
elem.clearContent();// clear the old value |
258 |
} |
211 |
} |
259 |
elem.addText(propsPart.getIdentifierProperty().getValue()); |
|
|
260 |
} |
261 |
|
212 |
|
262 |
/** |
213 |
/** |
263 |
* Add keywords property element if needed. |
214 |
* Add keywords property element if needed. |
264 |
*/ |
215 |
*/ |
265 |
private void addKeywords() { |
216 |
private void addKeywords() { |
266 |
if (!propsPart.getKeywordsProperty().hasValue()) |
217 |
setElementTextContent(KEYWORD_KEYWORDS, namespaceCoreProperties, propsPart.getKeywordsProperty()); |
267 |
return; |
|
|
268 |
|
269 |
Element elem = xmlDoc.getRootElement().element( |
270 |
new QName(KEYWORD_KEYWORDS, namespaceCoreProperties)); |
271 |
if (elem == null) { |
272 |
// missing, we add it |
273 |
elem = xmlDoc.getRootElement().addElement( |
274 |
new QName(KEYWORD_KEYWORDS, namespaceCoreProperties)); |
275 |
} else { |
276 |
elem.clearContent();// clear the old value |
277 |
} |
218 |
} |
278 |
elem.addText(propsPart.getKeywordsProperty().getValue()); |
|
|
279 |
} |
280 |
|
219 |
|
281 |
/** |
220 |
/** |
282 |
* Add language property element if needed. |
221 |
* Add language property element if needed. |
283 |
*/ |
222 |
*/ |
284 |
private void addLanguage() { |
223 |
private void addLanguage() { |
285 |
if (!propsPart.getLanguageProperty().hasValue()) |
224 |
setElementTextContent(KEYWORD_LANGUAGE, namespaceDC, propsPart.getLanguageProperty()); |
286 |
return; |
|
|
287 |
|
288 |
Element elem = xmlDoc.getRootElement().element( |
289 |
new QName(KEYWORD_LANGUAGE, namespaceDC)); |
290 |
if (elem == null) { |
291 |
// missing, we add it |
292 |
elem = xmlDoc.getRootElement().addElement( |
293 |
new QName(KEYWORD_LANGUAGE, namespaceDC)); |
294 |
} else { |
295 |
elem.clearContent();// clear the old value |
296 |
} |
225 |
} |
297 |
elem.addText(propsPart.getLanguageProperty().getValue()); |
|
|
298 |
} |
299 |
|
226 |
|
300 |
/** |
227 |
/** |
301 |
* Add 'last modified by' property if needed. |
228 |
* Add 'last modified by' property if needed. |
302 |
*/ |
229 |
*/ |
303 |
private void addLastModifiedBy() { |
230 |
private void addLastModifiedBy() { |
304 |
if (!propsPart.getLastModifiedByProperty().hasValue()) |
231 |
setElementTextContent(KEYWORD_LAST_MODIFIED_BY, namespaceCoreProperties, propsPart.getLastModifiedByProperty()); |
305 |
return; |
|
|
306 |
|
307 |
Element elem = xmlDoc.getRootElement().element( |
308 |
new QName(KEYWORD_LAST_MODIFIED_BY, namespaceCoreProperties)); |
309 |
if (elem == null) { |
310 |
// missing, we add it |
311 |
elem = xmlDoc.getRootElement() |
312 |
.addElement( |
313 |
new QName(KEYWORD_LAST_MODIFIED_BY, |
314 |
namespaceCoreProperties)); |
315 |
} else { |
316 |
elem.clearContent();// clear the old value |
317 |
} |
232 |
} |
318 |
elem.addText(propsPart.getLastModifiedByProperty().getValue()); |
|
|
319 |
} |
320 |
|
233 |
|
321 |
/** |
234 |
/** |
322 |
* Add 'last printed' property if needed. |
235 |
* Add 'last printed' property if needed. |
323 |
* |
236 |
* |
324 |
*/ |
237 |
*/ |
325 |
private void addLastPrinted() { |
238 |
private void addLastPrinted() { |
326 |
if (!propsPart.getLastPrintedProperty().hasValue()) |
239 |
setElementTextContent(KEYWORD_LAST_PRINTED, namespaceCoreProperties, propsPart.getLastPrintedProperty(), propsPart.getLastPrintedPropertyString()); |
327 |
return; |
|
|
328 |
|
329 |
Element elem = xmlDoc.getRootElement().element( |
330 |
new QName(KEYWORD_LAST_PRINTED, namespaceCoreProperties)); |
331 |
if (elem == null) { |
332 |
// missing, we add it |
333 |
elem = xmlDoc.getRootElement().addElement( |
334 |
new QName(KEYWORD_LAST_PRINTED, namespaceCoreProperties)); |
335 |
} else { |
336 |
elem.clearContent();// clear the old value |
337 |
} |
240 |
} |
338 |
elem.addText(propsPart.getLastPrintedPropertyString()); |
|
|
339 |
} |
340 |
|
241 |
|
341 |
/** |
242 |
/** |
342 |
* Add modified property element if needed. |
243 |
* Add modified property element if needed. |
343 |
*/ |
244 |
*/ |
344 |
private void addModified() { |
245 |
private void addModified() { |
345 |
if (!propsPart.getModifiedProperty().hasValue()) |
246 |
setElementTextContent(KEYWORD_MODIFIED, namespaceDcTerms, propsPart.getModifiedProperty(), |
346 |
return; |
247 |
propsPart.getModifiedPropertyString(), "dcterms:W3CDTF"); |
347 |
|
|
|
348 |
Element elem = xmlDoc.getRootElement().element( |
349 |
new QName(KEYWORD_MODIFIED, namespaceDcTerms)); |
350 |
if (elem == null) { |
351 |
// missing, we add it |
352 |
elem = xmlDoc.getRootElement().addElement( |
353 |
new QName(KEYWORD_MODIFIED, namespaceDcTerms)); |
354 |
} else { |
355 |
elem.clearContent();// clear the old value |
356 |
} |
248 |
} |
357 |
elem.addAttribute(new QName("type", namespaceXSI), "dcterms:W3CDTF"); |
|
|
358 |
elem.addText(propsPart.getModifiedPropertyString()); |
359 |
} |
360 |
|
249 |
|
361 |
/** |
250 |
/** |
362 |
* Add revision property if needed. |
251 |
* Add revision property if needed. |
363 |
*/ |
252 |
*/ |
364 |
private void addRevision() { |
253 |
private void addRevision() { |
365 |
if (!propsPart.getRevisionProperty().hasValue()) |
254 |
setElementTextContent(KEYWORD_REVISION, namespaceCoreProperties, propsPart.getRevisionProperty()); |
366 |
return; |
|
|
367 |
|
368 |
Element elem = xmlDoc.getRootElement().element( |
369 |
new QName(KEYWORD_REVISION, namespaceCoreProperties)); |
370 |
if (elem == null) { |
371 |
// missing, we add it |
372 |
elem = xmlDoc.getRootElement().addElement( |
373 |
new QName(KEYWORD_REVISION, namespaceCoreProperties)); |
374 |
} else { |
375 |
elem.clearContent();// clear the old value |
376 |
} |
255 |
} |
377 |
elem.addText(propsPart.getRevisionProperty().getValue()); |
|
|
378 |
} |
379 |
|
256 |
|
380 |
/** |
257 |
/** |
381 |
* Add subject property if needed. |
258 |
* Add subject property if needed. |
382 |
*/ |
259 |
*/ |
383 |
private void addSubject() { |
260 |
private void addSubject() { |
384 |
if (!propsPart.getSubjectProperty().hasValue()) |
261 |
setElementTextContent(KEYWORD_SUBJECT, namespaceDC, propsPart.getSubjectProperty()); |
385 |
return; |
|
|
386 |
|
387 |
Element elem = xmlDoc.getRootElement().element( |
388 |
new QName(KEYWORD_SUBJECT, namespaceDC)); |
389 |
if (elem == null) { |
390 |
// missing, we add it |
391 |
elem = xmlDoc.getRootElement().addElement( |
392 |
new QName(KEYWORD_SUBJECT, namespaceDC)); |
393 |
} else { |
394 |
elem.clearContent();// clear the old value |
395 |
} |
262 |
} |
396 |
elem.addText(propsPart.getSubjectProperty().getValue()); |
|
|
397 |
} |
398 |
|
263 |
|
399 |
/** |
264 |
/** |
400 |
* Add title property if needed. |
265 |
* Add title property if needed. |
401 |
*/ |
266 |
*/ |
402 |
private void addTitle() { |
267 |
private void addTitle() { |
403 |
if (!propsPart.getTitleProperty().hasValue()) |
268 |
setElementTextContent(KEYWORD_TITLE, namespaceDC, propsPart.getTitleProperty()); |
404 |
return; |
|
|
405 |
|
406 |
Element elem = xmlDoc.getRootElement().element( |
407 |
new QName(KEYWORD_TITLE, namespaceDC)); |
408 |
if (elem == null) { |
409 |
// missing, we add it |
410 |
elem = xmlDoc.getRootElement().addElement( |
411 |
new QName(KEYWORD_TITLE, namespaceDC)); |
412 |
} else { |
413 |
elem.clearContent();// clear the old value |
414 |
} |
269 |
} |
415 |
elem.addText(propsPart.getTitleProperty().getValue()); |
|
|
416 |
} |
417 |
|
270 |
|
418 |
private void addVersion() { |
271 |
private void addVersion() { |
419 |
if (!propsPart.getVersionProperty().hasValue()) |
272 |
setElementTextContent(KEYWORD_VERSION, namespaceCoreProperties, propsPart.getVersionProperty()); |
420 |
return; |
|
|
421 |
|
422 |
Element elem = xmlDoc.getRootElement().element( |
423 |
new QName(KEYWORD_VERSION, namespaceCoreProperties)); |
424 |
if (elem == null) { |
425 |
// missing, we add it |
426 |
elem = xmlDoc.getRootElement().addElement( |
427 |
new QName(KEYWORD_VERSION, namespaceCoreProperties)); |
428 |
} else { |
429 |
elem.clearContent();// clear the old value |
430 |
} |
431 |
elem.addText(propsPart.getVersionProperty().getValue()); |
432 |
} |
273 |
} |
433 |
} |
274 |
} |