1 | /* | |
2 | * Copyright OpenSearch Contributors | |
3 | * SPDX-License-Identifier: Apache-2.0 | |
4 | */ | |
5 | ||
6 | ||
7 | package org.opensearch.sql.expression.text; | |
8 | ||
9 | import static org.opensearch.sql.data.type.ExprCoreType.INTEGER; | |
10 | import static org.opensearch.sql.data.type.ExprCoreType.STRING; | |
11 | import static org.opensearch.sql.expression.function.FunctionDSL.define; | |
12 | import static org.opensearch.sql.expression.function.FunctionDSL.impl; | |
13 | import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandling; | |
14 | ||
15 | import lombok.experimental.UtilityClass; | |
16 | import org.opensearch.sql.data.model.ExprIntegerValue; | |
17 | import org.opensearch.sql.data.model.ExprStringValue; | |
18 | import org.opensearch.sql.data.model.ExprValue; | |
19 | import org.opensearch.sql.expression.function.BuiltinFunctionName; | |
20 | import org.opensearch.sql.expression.function.BuiltinFunctionRepository; | |
21 | import org.opensearch.sql.expression.function.DefaultFunctionResolver; | |
22 | import org.opensearch.sql.expression.function.FunctionName; | |
23 | import org.opensearch.sql.expression.function.SerializableBiFunction; | |
24 | import org.opensearch.sql.expression.function.SerializableTriFunction; | |
25 | ||
26 | ||
27 | /** | |
28 | * The definition of text functions. | |
29 | * 1) have the clear interface for function define. | |
30 | * 2) the implementation should rely on ExprValue. | |
31 | */ | |
32 | @UtilityClass | |
33 | public class TextFunction { | |
34 | private static String EMPTY_STRING = ""; | |
35 | ||
36 | /** | |
37 | * Register String Functions. | |
38 | * | |
39 | * @param repository {@link BuiltinFunctionRepository}. | |
40 | */ | |
41 | public void register(BuiltinFunctionRepository repository) { | |
42 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(substr()); |
43 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(substring()); |
44 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(ltrim()); |
45 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(rtrim()); |
46 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(trim()); |
47 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(lower()); |
48 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(upper()); |
49 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(concat()); |
50 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(concat_ws()); |
51 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(length()); |
52 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(strcmp()); |
53 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(right()); |
54 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(left()); |
55 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(ascii()); |
56 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(locate()); |
57 |
1
1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → SURVIVED |
repository.register(replace()); |
58 | } | |
59 | ||
60 | /** | |
61 | * Gets substring starting at given point, for optional given length. | |
62 | * Form of this function using keywords instead of comma delimited variables is not supported. | |
63 | * Supports following signatures: | |
64 | * (STRING, INTEGER)/(STRING, INTEGER, INTEGER) -> STRING | |
65 | */ | |
66 | private DefaultFunctionResolver substringSubstr(FunctionName functionName) { | |
67 |
1
1. substringSubstr : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::substringSubstr → KILLED |
return define(functionName, |
68 | impl(nullMissingHandling(TextFunction::exprSubstrStart), | |
69 | STRING, STRING, INTEGER), | |
70 | impl(nullMissingHandling(TextFunction::exprSubstrStartLength), | |
71 | STRING, STRING, INTEGER, INTEGER)); | |
72 | } | |
73 | ||
74 | private DefaultFunctionResolver substring() { | |
75 |
1
1. substring : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::substring → KILLED |
return substringSubstr(BuiltinFunctionName.SUBSTRING.getName()); |
76 | } | |
77 | ||
78 | private DefaultFunctionResolver substr() { | |
79 |
1
1. substr : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::substr → KILLED |
return substringSubstr(BuiltinFunctionName.SUBSTR.getName()); |
80 | } | |
81 | ||
82 | /** | |
83 | * Removes leading whitespace from string. | |
84 | * Supports following signatures: | |
85 | * STRING -> STRING | |
86 | */ | |
87 | private DefaultFunctionResolver ltrim() { | |
88 |
1
1. ltrim : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::ltrim → KILLED |
return define(BuiltinFunctionName.LTRIM.getName(), |
89 |
1
1. lambda$ltrim$12c7dc48$1 : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lambda$ltrim$12c7dc48$1 → KILLED |
impl(nullMissingHandling((v) -> new ExprStringValue(v.stringValue().stripLeading())), |
90 | STRING, STRING)); | |
91 | } | |
92 | ||
93 | /** | |
94 | * Removes trailing whitespace from string. | |
95 | * Supports following signatures: | |
96 | * STRING -> STRING | |
97 | */ | |
98 | private DefaultFunctionResolver rtrim() { | |
99 |
1
1. rtrim : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::rtrim → KILLED |
return define(BuiltinFunctionName.RTRIM.getName(), |
100 |
1
1. lambda$rtrim$12c7dc48$1 : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lambda$rtrim$12c7dc48$1 → KILLED |
impl(nullMissingHandling((v) -> new ExprStringValue(v.stringValue().stripTrailing())), |
101 | STRING, STRING)); | |
102 | } | |
103 | ||
104 | /** | |
105 | * Removes leading and trailing whitespace from string. | |
106 | * Has option to specify a String to trim instead of whitespace but this is not yet supported. | |
107 | * Supporting String specification requires finding keywords inside TRIM command. | |
108 | * Supports following signatures: | |
109 | * STRING -> STRING | |
110 | */ | |
111 | private DefaultFunctionResolver trim() { | |
112 |
1
1. trim : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::trim → KILLED |
return define(BuiltinFunctionName.TRIM.getName(), |
113 |
1
1. lambda$trim$12c7dc48$1 : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lambda$trim$12c7dc48$1 → KILLED |
impl(nullMissingHandling((v) -> new ExprStringValue(v.stringValue().trim())), |
114 | STRING, STRING)); | |
115 | } | |
116 | ||
117 | /** | |
118 | * Converts String to lowercase. | |
119 | * Supports following signatures: | |
120 | * STRING -> STRING | |
121 | */ | |
122 | private DefaultFunctionResolver lower() { | |
123 |
1
1. lower : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lower → KILLED |
return define(BuiltinFunctionName.LOWER.getName(), |
124 |
1
1. lambda$lower$12c7dc48$1 : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lambda$lower$12c7dc48$1 → KILLED |
impl(nullMissingHandling((v) -> new ExprStringValue((v.stringValue().toLowerCase()))), |
125 | STRING, STRING) | |
126 | ); | |
127 | } | |
128 | ||
129 | /** | |
130 | * Converts String to uppercase. | |
131 | * Supports following signatures: | |
132 | * STRING -> STRING | |
133 | */ | |
134 | private DefaultFunctionResolver upper() { | |
135 |
1
1. upper : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::upper → KILLED |
return define(BuiltinFunctionName.UPPER.getName(), |
136 |
1
1. lambda$upper$12c7dc48$1 : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lambda$upper$12c7dc48$1 → KILLED |
impl(nullMissingHandling((v) -> new ExprStringValue((v.stringValue().toUpperCase()))), |
137 | STRING, STRING) | |
138 | ); | |
139 | } | |
140 | ||
141 | /** | |
142 | * TODO: https://github.com/opendistro-for-elasticsearch/sql/issues/710 | |
143 | * Extend to accept variable argument amounts. | |
144 | * Concatenates a list of Strings. | |
145 | * Supports following signatures: | |
146 | * (STRING, STRING) -> STRING | |
147 | */ | |
148 | private DefaultFunctionResolver concat() { | |
149 |
1
1. concat : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::concat → KILLED |
return define(BuiltinFunctionName.CONCAT.getName(), |
150 | impl(nullMissingHandling((str1, str2) -> | |
151 |
1
1. lambda$concat$95048fc1$1 : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lambda$concat$95048fc1$1 → KILLED |
new ExprStringValue(str1.stringValue() + str2.stringValue())), STRING, STRING, STRING)); |
152 | } | |
153 | ||
154 | /** | |
155 | * TODO: https://github.com/opendistro-for-elasticsearch/sql/issues/710 | |
156 | * Extend to accept variable argument amounts. | |
157 | * Concatenates a list of Strings with a separator string. | |
158 | * Supports following signatures: | |
159 | * (STRING, STRING, STRING) -> STRING | |
160 | */ | |
161 | private DefaultFunctionResolver concat_ws() { | |
162 |
1
1. concat_ws : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::concat_ws → KILLED |
return define(BuiltinFunctionName.CONCAT_WS.getName(), |
163 | impl(nullMissingHandling((sep, str1, str2) -> | |
164 |
1
1. lambda$concat_ws$d3d4fc58$1 : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lambda$concat_ws$d3d4fc58$1 → KILLED |
new ExprStringValue(str1.stringValue() + sep.stringValue() + str2.stringValue())), |
165 | STRING, STRING, STRING, STRING)); | |
166 | } | |
167 | ||
168 | /** | |
169 | * Calculates length of String in bytes. | |
170 | * Supports following signatures: | |
171 | * STRING -> INTEGER | |
172 | */ | |
173 | private DefaultFunctionResolver length() { | |
174 |
1
1. length : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::length → KILLED |
return define(BuiltinFunctionName.LENGTH.getName(), |
175 | impl(nullMissingHandling((str) -> | |
176 |
1
1. lambda$length$12c7dc48$1 : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lambda$length$12c7dc48$1 → KILLED |
new ExprIntegerValue(str.stringValue().getBytes().length)), INTEGER, STRING)); |
177 | } | |
178 | ||
179 | /** | |
180 | * Does String comparison of two Strings and returns Integer value. | |
181 | * Supports following signatures: | |
182 | * (STRING, STRING) -> INTEGER | |
183 | */ | |
184 | private DefaultFunctionResolver strcmp() { | |
185 |
1
1. strcmp : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::strcmp → KILLED |
return define(BuiltinFunctionName.STRCMP.getName(), |
186 | impl(nullMissingHandling((str1, str2) -> | |
187 |
1
1. lambda$strcmp$95048fc1$1 : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::lambda$strcmp$95048fc1$1 → KILLED |
new ExprIntegerValue(Integer.compare( |
188 | str1.stringValue().compareTo(str2.stringValue()), 0))), | |
189 | INTEGER, STRING, STRING)); | |
190 | } | |
191 | ||
192 | /** | |
193 | * Returns the rightmost len characters from the string str, or NULL if any argument is NULL. | |
194 | * Supports following signatures: | |
195 | * (STRING, INTEGER) -> STRING | |
196 | */ | |
197 | private DefaultFunctionResolver right() { | |
198 |
1
1. right : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::right → KILLED |
return define(BuiltinFunctionName.RIGHT.getName(), |
199 | impl(nullMissingHandling(TextFunction::exprRight), STRING, STRING, INTEGER)); | |
200 | } | |
201 | ||
202 | /** | |
203 | * Returns the leftmost len characters from the string str, or NULL if any argument is NULL. | |
204 | * Supports following signature: | |
205 | * (STRING, INTEGER) -> STRING | |
206 | */ | |
207 | private DefaultFunctionResolver left() { | |
208 |
1
1. left : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::left → KILLED |
return define(BuiltinFunctionName.LEFT.getName(), |
209 | impl(nullMissingHandling(TextFunction::exprLeft), STRING, STRING, INTEGER)); | |
210 | } | |
211 | ||
212 | /** | |
213 | * Returns the numeric value of the leftmost character of the string str. | |
214 | * Returns 0 if str is the empty string. Returns NULL if str is NULL. | |
215 | * ASCII() works for 8-bit characters. | |
216 | * Supports following signature: | |
217 | * STRING -> INTEGER | |
218 | */ | |
219 | private DefaultFunctionResolver ascii() { | |
220 |
1
1. ascii : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::ascii → KILLED |
return define(BuiltinFunctionName.ASCII.getName(), |
221 | impl(nullMissingHandling(TextFunction::exprAscii), INTEGER, STRING)); | |
222 | } | |
223 | ||
224 | /** | |
225 | * LOCATE(substr, str) returns the position of the first occurrence of substring substr | |
226 | * in string str. LOCATE(substr, str, pos) returns the position of the first occurrence | |
227 | * of substring substr in string str, starting at position pos. | |
228 | * Returns 0 if substr is not in str. | |
229 | * Returns NULL if any argument is NULL. | |
230 | * Supports following signature: | |
231 | * (STRING, STRING) -> INTEGER | |
232 | * (STRING, STRING, INTEGER) -> INTEGER | |
233 | */ | |
234 | private DefaultFunctionResolver locate() { | |
235 |
1
1. locate : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::locate → KILLED |
return define(BuiltinFunctionName.LOCATE.getName(), |
236 | impl(nullMissingHandling( | |
237 | (SerializableBiFunction<ExprValue, ExprValue, ExprValue>) | |
238 | TextFunction::exprLocate), INTEGER, STRING, STRING), | |
239 | impl(nullMissingHandling( | |
240 | (SerializableTriFunction<ExprValue, ExprValue, ExprValue, ExprValue>) | |
241 | TextFunction::exprLocate), INTEGER, STRING, STRING, INTEGER)); | |
242 | } | |
243 | ||
244 | /** | |
245 | * REPLACE(str, from_str, to_str) returns the string str with all occurrences of | |
246 | * the string from_str replaced by the string to_str. | |
247 | * REPLACE() performs a case-sensitive match when searching for from_str. | |
248 | * Supports following signature: | |
249 | * (STRING, STRING, STRING) -> STRING | |
250 | */ | |
251 | private DefaultFunctionResolver replace() { | |
252 |
1
1. replace : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::replace → KILLED |
return define(BuiltinFunctionName.REPLACE.getName(), |
253 | impl(nullMissingHandling(TextFunction::exprReplace), STRING, STRING, STRING, STRING)); | |
254 | } | |
255 | ||
256 | private static ExprValue exprSubstrStart(ExprValue exprValue, ExprValue start) { | |
257 | int startIdx = start.integerValue(); | |
258 |
1
1. exprSubstrStart : negated conditional → KILLED |
if (startIdx == 0) { |
259 |
1
1. exprSubstrStart : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprSubstrStart → KILLED |
return new ExprStringValue(EMPTY_STRING); |
260 | } | |
261 | String str = exprValue.stringValue(); | |
262 |
1
1. exprSubstrStart : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprSubstrStart → KILLED |
return exprSubStr(str, startIdx, str.length()); |
263 | } | |
264 | ||
265 | private static ExprValue exprSubstrStartLength( | |
266 | ExprValue exprValue, ExprValue start, ExprValue length) { | |
267 | int startIdx = start.integerValue(); | |
268 | int len = length.integerValue(); | |
269 |
2
1. exprSubstrStartLength : negated conditional → KILLED 2. exprSubstrStartLength : negated conditional → KILLED |
if ((startIdx == 0) || (len == 0)) { |
270 |
1
1. exprSubstrStartLength : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprSubstrStartLength → KILLED |
return new ExprStringValue(EMPTY_STRING); |
271 | } | |
272 | String str = exprValue.stringValue(); | |
273 |
1
1. exprSubstrStartLength : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprSubstrStartLength → KILLED |
return exprSubStr(str, startIdx, len); |
274 | } | |
275 | ||
276 | private static ExprValue exprSubStr(String str, int start, int len) { | |
277 | // Correct negative start | |
278 |
4
1. exprSubStr : changed conditional boundary → SURVIVED 2. exprSubStr : Replaced integer subtraction with addition → KILLED 3. exprSubStr : Replaced integer addition with subtraction → KILLED 4. exprSubStr : negated conditional → KILLED |
start = (start > 0) ? (start - 1) : (str.length() + start); |
279 | ||
280 |
2
1. exprSubStr : changed conditional boundary → SURVIVED 2. exprSubStr : negated conditional → KILLED |
if (start > str.length()) { |
281 |
1
1. exprSubStr : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprSubStr → KILLED |
return new ExprStringValue(EMPTY_STRING); |
282 |
3
1. exprSubStr : changed conditional boundary → SURVIVED 2. exprSubStr : Replaced integer addition with subtraction → KILLED 3. exprSubStr : negated conditional → KILLED |
} else if ((start + len) > str.length()) { |
283 |
1
1. exprSubStr : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprSubStr → KILLED |
return new ExprStringValue(str.substring(start)); |
284 | } | |
285 |
2
1. exprSubStr : Replaced integer addition with subtraction → KILLED 2. exprSubStr : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprSubStr → KILLED |
return new ExprStringValue(str.substring(start, start + len)); |
286 | } | |
287 | ||
288 | private static ExprValue exprRight(ExprValue str, ExprValue len) { | |
289 |
2
1. exprRight : changed conditional boundary → SURVIVED 2. exprRight : negated conditional → KILLED |
if (len.integerValue() <= 0) { |
290 |
1
1. exprRight : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprRight → KILLED |
return new ExprStringValue(""); |
291 | } | |
292 | String stringValue = str.stringValue(); | |
293 |
1
1. exprRight : Replaced integer subtraction with addition → KILLED |
int left = Math.max(stringValue.length() - len.integerValue(), 0); |
294 |
1
1. exprRight : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprRight → KILLED |
return new ExprStringValue(str.stringValue().substring(left)); |
295 | } | |
296 | ||
297 | private static ExprValue exprLeft(ExprValue expr, ExprValue length) { | |
298 | String stringValue = expr.stringValue(); | |
299 | int right = length.integerValue(); | |
300 |
1
1. exprLeft : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprLeft → KILLED |
return new ExprStringValue(stringValue.substring(0, Math.min(right, stringValue.length()))); |
301 | } | |
302 | ||
303 | private static ExprValue exprAscii(ExprValue expr) { | |
304 |
1
1. exprAscii : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprAscii → KILLED |
return new ExprIntegerValue((int) expr.stringValue().charAt(0)); |
305 | } | |
306 | ||
307 | private static ExprValue exprLocate(ExprValue subStr, ExprValue str) { | |
308 |
2
1. exprLocate : Replaced integer addition with subtraction → KILLED 2. exprLocate : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprLocate → KILLED |
return new ExprIntegerValue(str.stringValue().indexOf(subStr.stringValue()) + 1); |
309 | } | |
310 | ||
311 | private static ExprValue exprLocate(ExprValue subStr, ExprValue str, ExprValue pos) { | |
312 |
1
1. exprLocate : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprLocate → KILLED |
return new ExprIntegerValue( |
313 |
2
1. exprLocate : Replaced integer subtraction with addition → SURVIVED 2. exprLocate : Replaced integer addition with subtraction → KILLED |
str.stringValue().indexOf(subStr.stringValue(), pos.integerValue() - 1) + 1); |
314 | } | |
315 | ||
316 | private static ExprValue exprReplace(ExprValue str, ExprValue from, ExprValue to) { | |
317 |
1
1. exprReplace : replaced return value with null for org/opensearch/sql/expression/text/TextFunction::exprReplace → KILLED |
return new ExprStringValue(str.stringValue().replaceAll(from.stringValue(), to.stringValue())); |
318 | } | |
319 | } | |
320 | ||
Mutations | ||
42 |
1.1 |
|
43 |
1.1 |
|
44 |
1.1 |
|
45 |
1.1 |
|
46 |
1.1 |
|
47 |
1.1 |
|
48 |
1.1 |
|
49 |
1.1 |
|
50 |
1.1 |
|
51 |
1.1 |
|
52 |
1.1 |
|
53 |
1.1 |
|
54 |
1.1 |
|
55 |
1.1 |
|
56 |
1.1 |
|
57 |
1.1 |
|
67 |
1.1 |
|
75 |
1.1 |
|
79 |
1.1 |
|
88 |
1.1 |
|
89 |
1.1 |
|
99 |
1.1 |
|
100 |
1.1 |
|
112 |
1.1 |
|
113 |
1.1 |
|
123 |
1.1 |
|
124 |
1.1 |
|
135 |
1.1 |
|
136 |
1.1 |
|
149 |
1.1 |
|
151 |
1.1 |
|
162 |
1.1 |
|
164 |
1.1 |
|
174 |
1.1 |
|
176 |
1.1 |
|
185 |
1.1 |
|
187 |
1.1 |
|
198 |
1.1 |
|
208 |
1.1 |
|
220 |
1.1 |
|
235 |
1.1 |
|
252 |
1.1 |
|
258 |
1.1 |
|
259 |
1.1 |
|
262 |
1.1 |
|
269 |
1.1 2.2 |
|
270 |
1.1 |
|
273 |
1.1 |
|
278 |
1.1 2.2 3.3 4.4 |
|
280 |
1.1 2.2 |
|
281 |
1.1 |
|
282 |
1.1 2.2 3.3 |
|
283 |
1.1 |
|
285 |
1.1 2.2 |
|
289 |
1.1 2.2 |
|
290 |
1.1 |
|
293 |
1.1 |
|
294 |
1.1 |
|
300 |
1.1 |
|
304 |
1.1 |
|
308 |
1.1 2.2 |
|
312 |
1.1 |
|
313 |
1.1 2.2 |
|
317 |
1.1 |