1 | /* | |
2 | * Copyright 2004 by Paulo Soares. | |
3 | * | |
4 | * The contents of this file are subject to the Mozilla Public License Version 1.1 | |
5 | * (the "License"); you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at http://www.mozilla.org/MPL/ | |
7 | * | |
8 | * Software distributed under the License is distributed on an "AS IS" basis, | |
9 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
10 | * for the specific language governing rights and limitations under the License. | |
11 | * | |
12 | * The Original Code is 'iText, a free JAVA-PDF library'. | |
13 | * | |
14 | * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by | |
15 | * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. | |
16 | * All Rights Reserved. | |
17 | * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer | |
18 | * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. | |
19 | * | |
20 | * Contributor(s): all the names of the contributors are added in the source code | |
21 | * where applicable. | |
22 | * | |
23 | * Alternatively, the contents of this file may be used under the terms of the | |
24 | * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the | |
25 | * provisions of LGPL are applicable instead of those above. If you wish to | |
26 | * allow use of your version of this file only under the terms of the LGPL | |
27 | * License and not to allow others to use your version of this file under | |
28 | * the MPL, indicate your decision by deleting the provisions above and | |
29 | * replace them with the notice and other provisions required by the LGPL. | |
30 | * If you do not delete the provisions above, a recipient may use your version | |
31 | * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. | |
32 | * | |
33 | * This library is free software; you can redistribute it and/or modify it | |
34 | * under the terms of the MPL as stated above or under the terms of the GNU | |
35 | * Library General Public License as published by the Free Software Foundation; | |
36 | * either version 2 of the License, or any later version. | |
37 | * | |
38 | * This library is distributed in the hope that it will be useful, but WITHOUT | |
39 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
40 | * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more | |
41 | * details. | |
42 | * | |
43 | * If you didn't download this code from the following link, you should check if | |
44 | * you aren't using an obsolete version: | |
45 | * http://www.lowagie.com/iText/ | |
46 | */ | |
47 | package com.lowagie.text.pdf; | |
48 | ||
49 | import java.io.BufferedWriter; | |
50 | import java.io.IOException; | |
51 | import java.io.InputStream; | |
52 | import java.io.OutputStream; | |
53 | import java.io.OutputStreamWriter; | |
54 | import java.io.Reader; | |
55 | import java.io.Writer; | |
56 | import java.util.HashMap; | |
57 | import java.util.Iterator; | |
58 | import java.util.Map; | |
59 | import java.util.StringTokenizer; | |
60 | import com.lowagie.text.error_messages.MessageLocalization; | |
61 | ||
62 | import com.lowagie.text.xml.simpleparser.IanaEncodings; | |
63 | import com.lowagie.text.xml.simpleparser.SimpleXMLDocHandler; | |
64 | import com.lowagie.text.xml.simpleparser.SimpleXMLParser; | |
65 | import com.lowagie.text.xml.XMLUtil; | |
66 | ||
67 | /** | |
68 | * | |
69 | * @author Paulo Soares (psoares@consiste.pt) | |
70 | */ | |
71 | public final class SimpleNamedDestination implements SimpleXMLDocHandler { | |
72 | | |
73 | private HashMap xmlNames; | |
74 | private Map<String, String> xmlLast; | |
75 | ||
76 | private SimpleNamedDestination() { | |
77 | } | |
78 | | |
79 | public static HashMap getNamedDestination(PdfReader reader, boolean fromNames) { | |
80 | IntHashtable pages = new IntHashtable(); | |
81 | int numPages = reader.getNumberOfPages(); | |
82 |
3
1. getNamedDestination : changed conditional boundary → NO_COVERAGE 2. getNamedDestination : Changed increment from 1 to -1 → NO_COVERAGE 3. getNamedDestination : negated conditional → NO_COVERAGE |
for (int k = 1; k <= numPages; ++k) |
83 | pages.put(reader.getPageOrigRef(k).getNumber(), k); | |
84 |
1
1. getNamedDestination : negated conditional → NO_COVERAGE |
HashMap names = fromNames ? reader.getNamedDestinationFromNames() : reader.getNamedDestinationFromStrings(); |
85 |
1
1. getNamedDestination : negated conditional → NO_COVERAGE |
for (Iterator it = names.entrySet().iterator(); it.hasNext();) { |
86 | Map.Entry entry = (Map.Entry)it.next(); | |
87 | PdfArray arr = (PdfArray)entry.getValue(); | |
88 | StringBuilder s = new StringBuilder(); | |
89 | try { | |
90 | s.append(pages.get(arr.getAsIndirectObject(0).getNumber())); | |
91 | s.append(' ').append(arr.getPdfObject(1).toString().substring(1)); | |
92 |
2
1. getNamedDestination : changed conditional boundary → NO_COVERAGE 2. getNamedDestination : negated conditional → NO_COVERAGE |
for (int k = 2; k < arr.size(); ++k) |
93 | s.append(' ').append(arr.getPdfObject(k).toString()); | |
94 | entry.setValue(s.toString()); | |
95 | } | |
96 | catch (Exception e) { | |
97 |
1
1. getNamedDestination : removed call to java/util/Iterator::remove → NO_COVERAGE |
it.remove(); |
98 | } | |
99 | } | |
100 |
1
1. getNamedDestination : mutated return of Object value for com/lowagie/text/pdf/SimpleNamedDestination::getNamedDestination to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return names; |
101 | } | |
102 | ||
103 | /** | |
104 | * Exports the destinations to XML. The DTD for this XML is: | |
105 | * <p> | |
106 | * <pre> | |
107 | * <?xml version='1.0' encoding='UTF-8'?> | |
108 | * <!ELEMENT Name (#PCDATA)> | |
109 | * <!ATTLIST Name | |
110 | * Page CDATA #IMPLIED | |
111 | * > | |
112 | * <!ELEMENT Destination (Name)*> | |
113 | * </pre> | |
114 | * @param names the names | |
115 | * @param out the export destination. The stream is not closed | |
116 | * @param encoding the encoding according to IANA conventions | |
117 | * @param onlyASCII codes above 127 will always be escaped with &#nn; if <CODE>true</CODE>, | |
118 | * whatever the encoding | |
119 | * @throws IOException on error | |
120 | */ | |
121 | public static void exportToXML(HashMap names, OutputStream out, String encoding, boolean onlyASCII) throws IOException { | |
122 | String jenc = IanaEncodings.getJavaEncoding(encoding); | |
123 | Writer wrt = new BufferedWriter(new OutputStreamWriter(out, jenc)); | |
124 |
1
1. exportToXML : removed call to com/lowagie/text/pdf/SimpleNamedDestination::exportToXML → NO_COVERAGE |
exportToXML(names, wrt, encoding, onlyASCII); |
125 | } | |
126 | ||
127 | /** | |
128 | * Exports the destinations to XML. | |
129 | * @param names the names | |
130 | * @param wrt the export destination. The writer is not closed | |
131 | * @param encoding the encoding according to IANA conventions | |
132 | * @param onlyASCII codes above 127 will always be escaped with &#nn; if <CODE>true</CODE>, | |
133 | * whatever the encoding | |
134 | * @throws IOException on error | |
135 | */ | |
136 | public static void exportToXML(HashMap names, Writer wrt, String encoding, boolean onlyASCII) throws IOException { | |
137 |
1
1. exportToXML : removed call to java/io/Writer::write → NO_COVERAGE |
wrt.write("<?xml version=\"1.0\" encoding=\""); |
138 |
1
1. exportToXML : removed call to java/io/Writer::write → NO_COVERAGE |
wrt.write(XMLUtil.escapeXML(encoding, onlyASCII)); |
139 |
1
1. exportToXML : removed call to java/io/Writer::write → NO_COVERAGE |
wrt.write("\"?>\n<Destination>\n"); |
140 | for (Object o : names.entrySet()) { | |
141 | Map.Entry entry = (Map.Entry) o; | |
142 | String key = (String) entry.getKey(); | |
143 | String value = (String) entry.getValue(); | |
144 |
1
1. exportToXML : removed call to java/io/Writer::write → NO_COVERAGE |
wrt.write(" <Name Page=\""); |
145 |
1
1. exportToXML : removed call to java/io/Writer::write → NO_COVERAGE |
wrt.write(XMLUtil.escapeXML(value, onlyASCII)); |
146 |
1
1. exportToXML : removed call to java/io/Writer::write → NO_COVERAGE |
wrt.write("\">"); |
147 |
1
1. exportToXML : removed call to java/io/Writer::write → NO_COVERAGE |
wrt.write(XMLUtil.escapeXML(escapeBinaryString(key), onlyASCII)); |
148 |
1
1. exportToXML : removed call to java/io/Writer::write → NO_COVERAGE |
wrt.write("</Name>\n"); |
149 | } | |
150 |
1
1. exportToXML : removed call to java/io/Writer::write → NO_COVERAGE |
wrt.write("</Destination>\n"); |
151 |
1
1. exportToXML : removed call to java/io/Writer::flush → NO_COVERAGE |
wrt.flush(); |
152 | } | |
153 | ||
154 | /** | |
155 | * Import the names from XML. | |
156 | * @param in the XML source. The stream is not closed | |
157 | * @throws IOException on error | |
158 | * @return the names | |
159 | */ | |
160 | public static HashMap importFromXML(InputStream in) throws IOException { | |
161 | SimpleNamedDestination names = new SimpleNamedDestination(); | |
162 |
1
1. importFromXML : removed call to com/lowagie/text/xml/simpleparser/SimpleXMLParser::parse → NO_COVERAGE |
SimpleXMLParser.parse(names, in); |
163 |
1
1. importFromXML : mutated return of Object value for com/lowagie/text/pdf/SimpleNamedDestination::importFromXML to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return names.xmlNames; |
164 | } | |
165 | ||
166 | /** | |
167 | * Import the names from XML. | |
168 | * @param in the XML source. The reader is not closed | |
169 | * @throws IOException on error | |
170 | * @return the names | |
171 | */ | |
172 | public static HashMap importFromXML(Reader in) throws IOException { | |
173 | SimpleNamedDestination names = new SimpleNamedDestination(); | |
174 |
1
1. importFromXML : removed call to com/lowagie/text/xml/simpleparser/SimpleXMLParser::parse → NO_COVERAGE |
SimpleXMLParser.parse(names, in); |
175 |
1
1. importFromXML : mutated return of Object value for com/lowagie/text/pdf/SimpleNamedDestination::importFromXML to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return names.xmlNames; |
176 | } | |
177 | ||
178 | static PdfArray createDestinationArray(String value, PdfWriter writer) { | |
179 | PdfArray ar = new PdfArray(); | |
180 | StringTokenizer tk = new StringTokenizer(value); | |
181 | int n = Integer.parseInt(tk.nextToken()); | |
182 | ar.add(writer.getPageReference(n)); | |
183 |
1
1. createDestinationArray : negated conditional → NO_COVERAGE |
if (!tk.hasMoreTokens()) { |
184 | ar.add(PdfName.XYZ); | |
185 | ar.add(new float[]{0, 10000, 0}); | |
186 | } | |
187 | else { | |
188 | String fn = tk.nextToken(); | |
189 |
1
1. createDestinationArray : negated conditional → NO_COVERAGE |
if (fn.startsWith("/")) |
190 | fn = fn.substring(1); | |
191 | ar.add(new PdfName(fn)); | |
192 |
4
1. createDestinationArray : changed conditional boundary → NO_COVERAGE 2. createDestinationArray : Changed increment from 1 to -1 → NO_COVERAGE 3. createDestinationArray : negated conditional → NO_COVERAGE 4. createDestinationArray : negated conditional → NO_COVERAGE |
for (int k = 0; k < 4 && tk.hasMoreTokens(); ++k) { |
193 | fn = tk.nextToken(); | |
194 |
1
1. createDestinationArray : negated conditional → NO_COVERAGE |
if (fn.equals("null")) |
195 | ar.add(PdfNull.PDFNULL); | |
196 | else | |
197 | ar.add(new PdfNumber(fn)); | |
198 | } | |
199 | } | |
200 |
1
1. createDestinationArray : mutated return of Object value for com/lowagie/text/pdf/SimpleNamedDestination::createDestinationArray to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return ar; |
201 | } | |
202 | ||
203 | public static PdfDictionary outputNamedDestinationAsNames(HashMap names, PdfWriter writer) { | |
204 | PdfDictionary dic = new PdfDictionary(); | |
205 | for (Object o : names.entrySet()) { | |
206 | Map.Entry entry = (Map.Entry) o; | |
207 | try { | |
208 | String key = (String) entry.getKey(); | |
209 | String value = (String) entry.getValue(); | |
210 | PdfArray ar = createDestinationArray(value, writer); | |
211 | PdfName kn = new PdfName(key); | |
212 |
1
1. outputNamedDestinationAsNames : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
dic.put(kn, ar); |
213 | } catch (Exception e) { | |
214 | // empty on purpose | |
215 | } | |
216 | } | |
217 |
1
1. outputNamedDestinationAsNames : mutated return of Object value for com/lowagie/text/pdf/SimpleNamedDestination::outputNamedDestinationAsNames to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return dic; |
218 | } | |
219 | ||
220 | public static PdfDictionary outputNamedDestinationAsStrings(HashMap names, PdfWriter writer) throws IOException { | |
221 | HashMap n2 = new HashMap(names); | |
222 |
1
1. outputNamedDestinationAsStrings : negated conditional → NO_COVERAGE |
for (Iterator it = n2.entrySet().iterator(); it.hasNext();) { |
223 | Map.Entry entry = (Map.Entry)it.next(); | |
224 | try { | |
225 | String value = (String)entry.getValue(); | |
226 | PdfArray ar = createDestinationArray(value, writer); | |
227 | entry.setValue(writer.addToBody(ar).getIndirectReference()); | |
228 | } | |
229 | catch (Exception e) { | |
230 |
1
1. outputNamedDestinationAsStrings : removed call to java/util/Iterator::remove → NO_COVERAGE |
it.remove(); |
231 | } | |
232 | } | |
233 |
1
1. outputNamedDestinationAsStrings : mutated return of Object value for com/lowagie/text/pdf/SimpleNamedDestination::outputNamedDestinationAsStrings to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return PdfNameTree.writeTree(n2, writer); |
234 | } | |
235 | ||
236 | public static String escapeBinaryString(String s) { | |
237 | StringBuilder buf = new StringBuilder(); | |
238 | char[] cc = s.toCharArray(); | |
239 | int len = cc.length; | |
240 | for (char c : cc) { | |
241 |
2
1. escapeBinaryString : changed conditional boundary → NO_COVERAGE 2. escapeBinaryString : negated conditional → NO_COVERAGE |
if (c < ' ') { |
242 | buf.append('\\'); | |
243 | String octal = "00" + Integer.toOctalString(c); | |
244 |
1
1. escapeBinaryString : Replaced integer subtraction with addition → NO_COVERAGE |
buf.append(octal.substring(octal.length() - 3)); |
245 |
1
1. escapeBinaryString : negated conditional → NO_COVERAGE |
} else if (c == '\\') |
246 | buf.append("\\\\"); | |
247 | else | |
248 | buf.append(c); | |
249 | } | |
250 |
1
1. escapeBinaryString : mutated return of Object value for com/lowagie/text/pdf/SimpleNamedDestination::escapeBinaryString to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return buf.toString(); |
251 | } | |
252 | ||
253 | public static String unEscapeBinaryString(String s) { | |
254 | StringBuilder buf = new StringBuilder(); | |
255 | char[] cc = s.toCharArray(); | |
256 | int len = cc.length; | |
257 |
3
1. unEscapeBinaryString : changed conditional boundary → NO_COVERAGE 2. unEscapeBinaryString : Changed increment from 1 to -1 → NO_COVERAGE 3. unEscapeBinaryString : negated conditional → NO_COVERAGE |
for (int k = 0; k < len; ++k) { |
258 | char c = cc[k]; | |
259 |
1
1. unEscapeBinaryString : negated conditional → NO_COVERAGE |
if (c == '\\') { |
260 |
3
1. unEscapeBinaryString : changed conditional boundary → NO_COVERAGE 2. unEscapeBinaryString : Changed increment from 1 to -1 → NO_COVERAGE 3. unEscapeBinaryString : negated conditional → NO_COVERAGE |
if (++k >= len) { |
261 | buf.append('\\'); | |
262 | break; | |
263 | } | |
264 | c = cc[k]; | |
265 |
4
1. unEscapeBinaryString : changed conditional boundary → NO_COVERAGE 2. unEscapeBinaryString : changed conditional boundary → NO_COVERAGE 3. unEscapeBinaryString : negated conditional → NO_COVERAGE 4. unEscapeBinaryString : negated conditional → NO_COVERAGE |
if (c >= '0' && c <= '7') { |
266 |
1
1. unEscapeBinaryString : Replaced integer subtraction with addition → NO_COVERAGE |
int n = c - '0'; |
267 |
1
1. unEscapeBinaryString : Changed increment from 1 to -1 → NO_COVERAGE |
++k; |
268 |
5
1. unEscapeBinaryString : changed conditional boundary → NO_COVERAGE 2. unEscapeBinaryString : changed conditional boundary → NO_COVERAGE 3. unEscapeBinaryString : Changed increment from 1 to -1 → NO_COVERAGE 4. unEscapeBinaryString : negated conditional → NO_COVERAGE 5. unEscapeBinaryString : negated conditional → NO_COVERAGE |
for (int j = 0; j < 2 && k < len; ++j) { |
269 | c = cc[k]; | |
270 |
4
1. unEscapeBinaryString : changed conditional boundary → NO_COVERAGE 2. unEscapeBinaryString : changed conditional boundary → NO_COVERAGE 3. unEscapeBinaryString : negated conditional → NO_COVERAGE 4. unEscapeBinaryString : negated conditional → NO_COVERAGE |
if (c >= '0' && c <= '7') { |
271 |
1
1. unEscapeBinaryString : Changed increment from 1 to -1 → NO_COVERAGE |
++k; |
272 |
3
1. unEscapeBinaryString : Replaced integer multiplication with division → NO_COVERAGE 2. unEscapeBinaryString : Replaced integer addition with subtraction → NO_COVERAGE 3. unEscapeBinaryString : Replaced integer subtraction with addition → NO_COVERAGE |
n = n * 8 + c - '0'; |
273 | } | |
274 | else { | |
275 | break; | |
276 | } | |
277 | } | |
278 |
1
1. unEscapeBinaryString : Changed increment from -1 to 1 → NO_COVERAGE |
--k; |
279 | buf.append((char)n); | |
280 | } | |
281 | else | |
282 | buf.append(c); | |
283 | } | |
284 | else | |
285 | buf.append(c); | |
286 | } | |
287 |
1
1. unEscapeBinaryString : mutated return of Object value for com/lowagie/text/pdf/SimpleNamedDestination::unEscapeBinaryString to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return buf.toString(); |
288 | } | |
289 | ||
290 | public void endDocument() { | |
291 | } | |
292 | ||
293 | public void endElement(String tag) { | |
294 |
1
1. endElement : negated conditional → NO_COVERAGE |
if (tag.equals("Destination")) { |
295 |
2
1. endElement : negated conditional → NO_COVERAGE 2. endElement : negated conditional → NO_COVERAGE |
if (xmlLast == null && xmlNames != null) |
296 | return; | |
297 | else | |
298 | throw new RuntimeException(MessageLocalization.getComposedMessage("destination.end.tag.out.of.place")); | |
299 | } | |
300 |
1
1. endElement : negated conditional → NO_COVERAGE |
if (!tag.equals("Name")) |
301 | throw new RuntimeException(MessageLocalization.getComposedMessage("invalid.end.tag.1", tag)); | |
302 |
2
1. endElement : negated conditional → NO_COVERAGE 2. endElement : negated conditional → NO_COVERAGE |
if (xmlLast == null || xmlNames == null) |
303 | throw new RuntimeException(MessageLocalization.getComposedMessage("name.end.tag.out.of.place")); | |
304 |
1
1. endElement : negated conditional → NO_COVERAGE |
if (!xmlLast.containsKey("Page")) |
305 | throw new RuntimeException(MessageLocalization.getComposedMessage("page.attribute.missing")); | |
306 | xmlNames.put(unEscapeBinaryString((String)xmlLast.get("Name")), xmlLast.get("Page")); | |
307 | xmlLast = null; | |
308 | } | |
309 | ||
310 | public void startDocument() { | |
311 | } | |
312 | ||
313 | public void startElement(String tag, Map<String, String> h) { | |
314 |
1
1. startElement : negated conditional → NO_COVERAGE |
if (xmlNames == null) { |
315 |
1
1. startElement : negated conditional → NO_COVERAGE |
if (tag.equals("Destination")) { |
316 | xmlNames = new HashMap(); | |
317 | return; | |
318 | } | |
319 | else | |
320 | throw new RuntimeException(MessageLocalization.getComposedMessage("root.element.is.not.destination")); | |
321 | } | |
322 |
1
1. startElement : negated conditional → NO_COVERAGE |
if (!tag.equals("Name")) |
323 | throw new RuntimeException(MessageLocalization.getComposedMessage("tag.1.not.allowed", tag)); | |
324 |
1
1. startElement : negated conditional → NO_COVERAGE |
if (xmlLast != null) |
325 | throw new RuntimeException(MessageLocalization.getComposedMessage("nested.tags.are.not.allowed")); | |
326 | xmlLast = new HashMap(h); | |
327 | xmlLast.put("Name", ""); | |
328 | } | |
329 | ||
330 | public void text(String str) { | |
331 |
1
1. text : negated conditional → NO_COVERAGE |
if (xmlLast == null) |
332 | return; | |
333 | String name = (String)xmlLast.get("Name"); | |
334 | name += str; | |
335 | xmlLast.put("Name", name); | |
336 | } | |
337 | } | |
Mutations | ||
82 |
1.1 2.2 3.3 |
|
84 |
1.1 |
|
85 |
1.1 |
|
92 |
1.1 2.2 |
|
97 |
1.1 |
|
100 |
1.1 |
|
124 |
1.1 |
|
137 |
1.1 |
|
138 |
1.1 |
|
139 |
1.1 |
|
144 |
1.1 |
|
145 |
1.1 |
|
146 |
1.1 |
|
147 |
1.1 |
|
148 |
1.1 |
|
150 |
1.1 |
|
151 |
1.1 |
|
162 |
1.1 |
|
163 |
1.1 |
|
174 |
1.1 |
|
175 |
1.1 |
|
183 |
1.1 |
|
189 |
1.1 |
|
192 |
1.1 2.2 3.3 4.4 |
|
194 |
1.1 |
|
200 |
1.1 |
|
212 |
1.1 |
|
217 |
1.1 |
|
222 |
1.1 |
|
230 |
1.1 |
|
233 |
1.1 |
|
241 |
1.1 2.2 |
|
244 |
1.1 |
|
245 |
1.1 |
|
250 |
1.1 |
|
257 |
1.1 2.2 3.3 |
|
259 |
1.1 |
|
260 |
1.1 2.2 3.3 |
|
265 |
1.1 2.2 3.3 4.4 |
|
266 |
1.1 |
|
267 |
1.1 |
|
268 |
1.1 2.2 3.3 4.4 5.5 |
|
270 |
1.1 2.2 3.3 4.4 |
|
271 |
1.1 |
|
272 |
1.1 2.2 3.3 |
|
278 |
1.1 |
|
287 |
1.1 |
|
294 |
1.1 |
|
295 |
1.1 2.2 |
|
300 |
1.1 |
|
302 |
1.1 2.2 |
|
304 |
1.1 |
|
314 |
1.1 |
|
315 |
1.1 |
|
322 |
1.1 |
|
324 |
1.1 |
|
331 |
1.1 |