| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
| QueueMap |
|
| 1.9642857142857142;1.964 |
| 1 | /* |
|
| 2 | Wotonomy: OpenStep design patterns for pure Java applications. |
|
| 3 | Copyright (C) 2000 Blacksmith, Inc. |
|
| 4 | ||
| 5 | This library is free software; you can redistribute it and/or |
|
| 6 | modify it under the terms of the GNU Lesser General Public |
|
| 7 | License as published by the Free Software Foundation; either |
|
| 8 | version 2.1 of the License, or (at your option) any later version. |
|
| 9 | ||
| 10 | This library is distributed in the hope that it will be useful, |
|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 13 | Lesser General Public License for more details. |
|
| 14 | ||
| 15 | You should have received a copy of the GNU Lesser General Public |
|
| 16 | License along with this library; if not, see http://www.gnu.org |
|
| 17 | */ |
|
| 18 | ||
| 19 | package net.wotonomy.foundation.internal; |
|
| 20 | ||
| 21 | import java.util.*; //collections |
|
| 22 | ||
| 23 | /** |
|
| 24 | * A queue based implementation of the Map interface. This class provides for |
|
| 25 | * all the opertions of a map, but keeps the entries in the same sequence as |
|
| 26 | * originally added. The first entry placed in the map will be the first |
|
| 27 | * entry retreived during iteration: first-in, first-out (FIFO). <BR><BR> |
|
| 28 | * |
|
| 29 | * Keys cannot be duplicated. If an entry is made using a key that already |
|
| 30 | * exists, the value for that key will be replaced with that new value. There |
|
| 31 | * are no such restrictions on the values. The values may be null. <BR><BR> |
|
| 32 | * |
|
| 33 | * Some convenience methods are provided for the queue type operations. The |
|
| 34 | * first key can be retreived as well as the last key. A key can be used |
|
| 35 | * to retreive its corresponding value from the map. A value can also be used |
|
| 36 | * to retreive its key from the map, however, since there may be multiple values |
|
| 37 | * of the same equality, the first key found will be returned. <BR><BR> |
|
| 38 | * |
|
| 39 | * @author rglista@blacksmith.com |
|
| 40 | * @author mpowers@blacksmith.com |
|
| 41 | * @date $Date: 2006-02-18 22:41:36 +0000 (Sat, 18 Feb 2006) $ |
|
| 42 | * @revision $Revision: 899 $ |
|
| 43 | */ |
|
| 44 | public class QueueMap implements Map |
|
| 45 | { |
|
| 46 | List values; |
|
| 47 | List keys; |
|
| 48 | Map keyToValue; |
|
| 49 | ||
| 50 | /** |
|
| 51 | * Creates an empty QueueMap. |
|
| 52 | */ |
|
| 53 | 0 | public QueueMap() |
| 54 | 0 | { |
| 55 | 0 | values = new LinkedList(); |
| 56 | 0 | keys = new LinkedList(); |
| 57 | 0 | keyToValue = new HashMap(); |
| 58 | 0 | } |
| 59 | ||
| 60 | /** |
|
| 61 | * Creates a QueueMap and places the entries from the passed in map into this map. |
|
| 62 | * The order of the entries is based on however the iterator iteratated through |
|
| 63 | * the map entries. |
|
| 64 | * @param t A map object. |
|
| 65 | */ |
|
| 66 | 0 | public QueueMap( Map t ) |
| 67 | 0 | { |
| 68 | 0 | values = new ArrayList(); |
| 69 | 0 | keys = new ArrayList(); |
| 70 | 0 | keyToValue = new HashMap(); |
| 71 | ||
| 72 | 0 | putAll( t ); |
| 73 | 0 | } |
| 74 | ||
| 75 | /** |
|
| 76 | * Removes all the entries from this map. |
|
| 77 | */ |
|
| 78 | public void clear() |
|
| 79 | { |
|
| 80 | 0 | values.clear(); |
| 81 | 0 | keys.clear(); |
| 82 | 0 | keyToValue.clear(); |
| 83 | 0 | } |
| 84 | ||
| 85 | /** |
|
| 86 | * Tests to see if the key is contained in the map. If the key is present in |
|
| 87 | * the map, then TRUE is returned, otherwise FALSE is returned. The equals() |
|
| 88 | * operation is used to determine equality. |
|
| 89 | * @return True if the map contains the given key, false otherwise. |
|
| 90 | */ |
|
| 91 | public boolean containsKey( Object key ) |
|
| 92 | { |
|
| 93 | 0 | return keyToValue.containsKey( key ); |
| 94 | } |
|
| 95 | ||
| 96 | /** |
|
| 97 | * Tests to see if the value is contained in the map. If the value is present in |
|
| 98 | * the map, then TRUE is returned, otherwise FALSE is returned. The equals() |
|
| 99 | * operation is used to determine equality. The value can be null and will |
|
| 100 | * return TRUE if null is a value in the map. If TRUE is returned, then there |
|
| 101 | * may be more than one values in the map. |
|
| 102 | * @return True if the map contains the given value, false otherwise. |
|
| 103 | */ |
|
| 104 | public boolean containsValue( Object value ) |
|
| 105 | { |
|
| 106 | 0 | return keyToValue.containsValue( value ); |
| 107 | } |
|
| 108 | ||
| 109 | /** |
|
| 110 | * Returns a set view of the mappings contained in this map. Each element |
|
| 111 | * in the returned set is a <tt>Map.Entry</tt>. The returned set is NOT backed |
|
| 112 | * by the map, so changes to the map are NOT reflected in the set, and vice-versa. |
|
| 113 | * The returned set is independent of this Map and its underlying structure. |
|
| 114 | * |
|
| 115 | * @return a set view of the mappings contained in this map. |
|
| 116 | */ |
|
| 117 | public Set entrySet() |
|
| 118 | { |
|
| 119 | 0 | Set result = new HashSet(keys.size(), 1F); |
| 120 | ||
| 121 | 0 | for ( int i = 0; i < keys.size(); i++ ) |
| 122 | { |
|
| 123 | 0 | result.add( new KeyValuePair( keys.get(i), values.get(i) ) ); |
| 124 | } |
|
| 125 | ||
| 126 | 0 | return result; |
| 127 | } |
|
| 128 | ||
| 129 | /** |
|
| 130 | * Compares the specified object with this map for equality. Returns |
|
| 131 | * <tt>true</tt> if the given object is also a map and the two Maps |
|
| 132 | * represent the same mappings. More formally, two maps <tt>t1</tt> and |
|
| 133 | * <tt>t2</tt> represent the same mappings if |
|
| 134 | * <tt>t1.entrySet().equals(t2.entrySet())</tt>. This ensures that the |
|
| 135 | * <tt>equals</tt> method works properly across different implementations |
|
| 136 | * of the <tt>Map</tt> interface. |
|
| 137 | * |
|
| 138 | * @param o object to be compared for equality with this map. |
|
| 139 | * @return <tt>true</tt> if the specified object is equal to this map. |
|
| 140 | */ |
|
| 141 | public boolean equals( Object o ) |
|
| 142 | { |
|
| 143 | 0 | return keyToValue.equals( o ); |
| 144 | } |
|
| 145 | ||
| 146 | /** |
|
| 147 | * Returns the corresponding value for the given key. The returned value may be |
|
| 148 | * null as that is a legal value in this map. However, if the key is not |
|
| 149 | * contained in this map then null is also returned. Use the containsKey() |
|
| 150 | * method to distinguish between the two cases. |
|
| 151 | * @param key A key into the map. |
|
| 152 | * @return The value corresponding to the key (can be null), or null if the key |
|
| 153 | * is not contained in the map. |
|
| 154 | */ |
|
| 155 | public Object get( Object key ) |
|
| 156 | { |
|
| 157 | 0 | return keyToValue.get( key ); |
| 158 | } |
|
| 159 | ||
| 160 | /** |
|
| 161 | * Returns the hash code value for this map. The hash code of a map |
|
| 162 | * is defined to be the sum of the hashCodes of each entry in the map's |
|
| 163 | * entrySet view. This ensures that <tt>t1.equals(t2)</tt> implies |
|
| 164 | * that <tt>t1.hashCode()==t2.hashCode()</tt> for any two maps |
|
| 165 | * <tt>t1</tt> and <tt>t2</tt>, as required by the general |
|
| 166 | * contract of Object.hashCode. |
|
| 167 | * |
|
| 168 | * @return the hash code value for this map. |
|
| 169 | */ |
|
| 170 | public int hashCode() |
|
| 171 | { |
|
| 172 | 0 | return keyToValue.hashCode(); |
| 173 | } |
|
| 174 | ||
| 175 | /** |
|
| 176 | * Returns true is this map contains no key-value mappings. |
|
| 177 | * @return True is this map contains no entries, false otherwise. |
|
| 178 | */ |
|
| 179 | public boolean isEmpty() |
|
| 180 | { |
|
| 181 | 0 | return keyToValue.isEmpty(); |
| 182 | } |
|
| 183 | ||
| 184 | /** |
|
| 185 | * Returns the keys used in the map. There is no order implied in the returned |
|
| 186 | * set and may be different than the the order in which they were inserted. |
|
| 187 | * @return A Set containing all the keys used in the map. |
|
| 188 | */ |
|
| 189 | public Set keySet() |
|
| 190 | { |
|
| 191 | 0 | Set result = new HashSet(keys.size(), 1F); |
| 192 | ||
| 193 | 0 | for ( int i = 0; i < keys.size(); i++ ) |
| 194 | { |
|
| 195 | 0 | result.add( keys.get(i) ); |
| 196 | } |
|
| 197 | ||
| 198 | 0 | return result; |
| 199 | } |
|
| 200 | ||
| 201 | /** |
|
| 202 | * Places the key/value entry into the map at the end position. If the key |
|
| 203 | * already exists in the map, then its value is replaced by the new given |
|
| 204 | * value. The mapping does not change order in this case. The specified |
|
| 205 | * key cannot be null. |
|
| 206 | * @param key The key to place into the map, cannot be null. |
|
| 207 | * @param value The value to associate with the key, may be null. |
|
| 208 | * @return Null if the key is new, the replaced value if the key already |
|
| 209 | * existed. (Note: If the key was null, then null is returned.) |
|
| 210 | */ |
|
| 211 | public Object put( Object key, Object value ) |
|
| 212 | { |
|
| 213 | 0 | if ( key == null ) return null; |
| 214 | ||
| 215 | 0 | if ( keys.contains( key ) ) |
| 216 | { |
|
| 217 | 0 | values.remove( keys.indexOf( key ) ); |
| 218 | 0 | values.add( keys.indexOf( key ), value ); |
| 219 | 0 | } |
| 220 | else |
|
| 221 | { |
|
| 222 | 0 | values.add( value ); |
| 223 | 0 | keys.add( key ); |
| 224 | } |
|
| 225 | ||
| 226 | 0 | return keyToValue.put( key, value ); |
| 227 | } |
|
| 228 | ||
| 229 | /** |
|
| 230 | * Places all the entries from this given map into this map. If the keys |
|
| 231 | * already exist, then there values are replaced. |
|
| 232 | * @param t A map of key/value entries. |
|
| 233 | */ |
|
| 234 | public void putAll( Map t ) |
|
| 235 | { |
|
| 236 | 0 | if ( t == null ) |
| 237 | { |
|
| 238 | // Nothing to do! |
|
| 239 | 0 | return; |
| 240 | } |
|
| 241 | ||
| 242 | // Place the entries from the passed in map into this map. |
|
| 243 | 0 | for ( Iterator it = t.keySet().iterator(); it.hasNext(); ) |
| 244 | { |
|
| 245 | 0 | Object aKey = it.next(); |
| 246 | 0 | put( aKey, t.get( aKey ) ); |
| 247 | 0 | } |
| 248 | 0 | } |
| 249 | ||
| 250 | /** |
|
| 251 | * Remove the mapping of the key and associated value from this map. |
|
| 252 | * Note: null is a valid value in the map. |
|
| 253 | * @param key A key to remove from the map, cannot be null. |
|
| 254 | * @return The value of the removed mapping, null if the mapping did not exist. |
|
| 255 | * Null could also be returned if the associated value of the key was null. |
|
| 256 | */ |
|
| 257 | public Object remove( Object key ) |
|
| 258 | { |
|
| 259 | 0 | if ( key == null ) return null; |
| 260 | ||
| 261 | 0 | Object value = null; |
| 262 | ||
| 263 | 0 | if ( containsKey( key ) ) |
| 264 | { |
|
| 265 | 0 | value = keyToValue.remove( key ); |
| 266 | 0 | int i = values.indexOf( value ); |
| 267 | 0 | if ( i != -1 ) |
| 268 | { |
|
| 269 | 0 | keys.remove( i ); |
| 270 | 0 | values.remove( i ); |
| 271 | } |
|
| 272 | } |
|
| 273 | ||
| 274 | 0 | return value; |
| 275 | } |
|
| 276 | ||
| 277 | /** |
|
| 278 | * Returns the number of key/value pairs in this map. |
|
| 279 | * @return The number of pairs. |
|
| 280 | */ |
|
| 281 | public int size() |
|
| 282 | { |
|
| 283 | 0 | return values.size(); |
| 284 | } |
|
| 285 | ||
| 286 | /** |
|
| 287 | * Returns an ordered list of keys from the map. The order is the same |
|
| 288 | * as the added order of the mapped items.<br> |
|
| 289 | * NOTE: The returned list is the underlying keys list used by this class. |
|
| 290 | * If modification are to be made to this list, it should be cloned first. |
|
| 291 | * @return An ordered list of keys. |
|
| 292 | */ |
|
| 293 | public List keys() |
|
| 294 | { |
|
| 295 | 0 | return keys; |
| 296 | } |
|
| 297 | ||
| 298 | /** |
|
| 299 | * Returns an ordered list of values from the map. The order is the same |
|
| 300 | * as the added order of the mapped items. |
|
| 301 | * NOTE: The returned list is the underlying keys list used by this class. |
|
| 302 | * If modification are to be made to this list, it should be cloned first. |
|
| 303 | * @return An ordered list of values. |
|
| 304 | */ |
|
| 305 | public Collection values() |
|
| 306 | { |
|
| 307 | 0 | return values; |
| 308 | } |
|
| 309 | ||
| 310 | /** |
|
| 311 | * Returns the corresponding value for the given key. The returned value may be |
|
| 312 | * null as that is a legal value in this map. However, if the key is not |
|
| 313 | * contained in this map then null is also returned. Use the containsKey() |
|
| 314 | * method to distinguish between the two cases. |
|
| 315 | * @param key A key into the map. |
|
| 316 | * @return The value corresponding to the key (can be null), or null if the key |
|
| 317 | * is not contained in the map. |
|
| 318 | */ |
|
| 319 | public Object getValueForKey( Object key ) |
|
| 320 | { |
|
| 321 | 0 | return keyToValue.get( key ); |
| 322 | } |
|
| 323 | ||
| 324 | /** |
|
| 325 | * Returns the associated key for this value. Since there may be more than one |
|
| 326 | * of the same value in the map, this returns the first key associated with this |
|
| 327 | * value. Null is returned if the value is not in the map. |
|
| 328 | * @param value A value that is contained in this map. |
|
| 329 | * @return A first key that corresponds to this value. |
|
| 330 | */ |
|
| 331 | public Object getKeyForValue( Object value ) |
|
| 332 | { |
|
| 333 | 0 | int i = values.indexOf( value ); |
| 334 | 0 | if ( i != -1 ) |
| 335 | { |
|
| 336 | 0 | return keys.get( i ); |
| 337 | } |
|
| 338 | 0 | return null; |
| 339 | } |
|
| 340 | ||
| 341 | /** |
|
| 342 | * Returns the first key in the map. If the map is empty, then null is |
|
| 343 | * returned. |
|
| 344 | * @return The first key in the map, null if there are no mappings. |
|
| 345 | */ |
|
| 346 | public Object getFirstKey() |
|
| 347 | { |
|
| 348 | 0 | if ( keys.size() < 1 ) |
| 349 | { |
|
| 350 | 0 | return null; |
| 351 | } |
|
| 352 | 0 | return keys.get(0); |
| 353 | } |
|
| 354 | ||
| 355 | /** |
|
| 356 | * Returns the last key in the map. If the map is empty, then null is |
|
| 357 | * returned. |
|
| 358 | * @return The last key in the map, null if there are no mappings. |
|
| 359 | */ |
|
| 360 | public Object getLastKey() |
|
| 361 | { |
|
| 362 | 0 | if ( keys.size() < 1 ) |
| 363 | { |
|
| 364 | 0 | return null; |
| 365 | } |
|
| 366 | 0 | return keys.get( keys.size() -1 ); |
| 367 | } |
|
| 368 | ||
| 369 | /** |
|
| 370 | * This class contains a key/value pair. The key must be a valid object, |
|
| 371 | * it cannot be null. The value can be a valid object or null. |
|
| 372 | */ |
|
| 373 | static public class KeyValuePair implements Map.Entry |
|
| 374 | { |
|
| 375 | Object key; |
|
| 376 | Object value; |
|
| 377 | ||
| 378 | /** |
|
| 379 | * Default constructor. The constructor takes the key and value as parameters. |
|
| 380 | * Since the key cannot be null, it must be specified during initialization. |
|
| 381 | * The value can be null. |
|
| 382 | * @param key The key object of this pair. The key cannot be null. |
|
| 383 | * @param value The value object of this pair. The value can be null. |
|
| 384 | */ |
|
| 385 | 0 | public KeyValuePair( Object aKey, Object aValue ) |
| 386 | 0 | { |
| 387 | 0 | key = aKey; |
| 388 | 0 | value = aValue; |
| 389 | 0 | } |
| 390 | ||
| 391 | /** |
|
| 392 | * Returns the key object of this pair. |
|
| 393 | * @return The key object. |
|
| 394 | */ |
|
| 395 | public Object getKey() |
|
| 396 | { |
|
| 397 | 0 | return key; |
| 398 | } |
|
| 399 | ||
| 400 | /** |
|
| 401 | * Returns the the value object of this pair. May be null. |
|
| 402 | * @return The value object. |
|
| 403 | */ |
|
| 404 | public Object getValue() |
|
| 405 | { |
|
| 406 | 0 | return value; |
| 407 | } |
|
| 408 | ||
| 409 | /** |
|
| 410 | * Sets the value object of this pair. May be an object or null. |
|
| 411 | * @param aValue The value object to place into this pair. |
|
| 412 | */ |
|
| 413 | public Object setValue( Object aValue ) |
|
| 414 | { |
|
| 415 | 0 | Object result = value; |
| 416 | 0 | value = aValue; |
| 417 | 0 | return result; |
| 418 | } |
|
| 419 | ||
| 420 | public boolean equals( Object o ) |
|
| 421 | { |
|
| 422 | 0 | if ( o instanceof KeyValuePair ) |
| 423 | { |
|
| 424 | 0 | KeyValuePair p = (KeyValuePair) o; |
| 425 | 0 | if ( ( key.equals( p.getKey() ) ) && ( value.equals( p.getValue() ) ) ) |
| 426 | { |
|
| 427 | 0 | return true; |
| 428 | } |
|
| 429 | } |
|
| 430 | 0 | return false; |
| 431 | } |
|
| 432 | } |
|
| 433 | ||
| 434 | /** |
|
| 435 | * Returns a string reprsentation of this class. The contents of the |
|
| 436 | * map are placed in the string in its proper order. |
|
| 437 | */ |
|
| 438 | public String toString() |
|
| 439 | { |
|
| 440 | 0 | int max = size() - 1; |
| 441 | 0 | StringBuffer buf = new StringBuffer(); |
| 442 | ||
| 443 | 0 | buf.append("{"); |
| 444 | 0 | for (int j = 0; j <= max; j++) |
| 445 | { |
|
| 446 | 0 | buf.append(keys.get(j) + "=" + values.get(j)); |
| 447 | 0 | if (j < max) |
| 448 | { |
|
| 449 | 0 | buf.append(", "); |
| 450 | } |
|
| 451 | } |
|
| 452 | 0 | buf.append("}"); |
| 453 | ||
| 454 | 0 | return buf.toString(); |
| 455 | } |
|
| 456 | ||
| 457 | // unit test |
|
| 458 | public static void main( String[] argv ) |
|
| 459 | { |
|
| 460 | QueueMap qMap; |
|
| 461 | ||
| 462 | 0 | qMap = new QueueMap(); |
| 463 | 0 | for (int i = 0; i < 5; i++) |
| 464 | { |
|
| 465 | 0 | qMap.put(Integer.toString(i), Integer.toString(i)); |
| 466 | } |
|
| 467 | 0 | System.out.println("\nMap = " + qMap); |
| 468 | 0 | System.out.println("Keys = " + qMap.keys()); |
| 469 | 0 | System.out.println("Values = " + qMap.values()); |
| 470 | ||
| 471 | 0 | qMap = new QueueMap(); |
| 472 | 0 | for (int i = 0; i < 5; i++) |
| 473 | { |
|
| 474 | 0 | qMap.put(Integer.toString(i), "A"); |
| 475 | } |
|
| 476 | 0 | System.out.println("\nMap = " + qMap); |
| 477 | 0 | System.out.println("Keys = " + qMap.keys()); |
| 478 | 0 | System.out.println("Values = " + qMap.values()); |
| 479 | ||
| 480 | 0 | qMap = new QueueMap(); |
| 481 | 0 | for (int i = 0; i < 5; i++) |
| 482 | { |
|
| 483 | 0 | qMap.put(Integer.toString(i), null); |
| 484 | } |
|
| 485 | 0 | System.out.println("\nMap = " + qMap); |
| 486 | 0 | System.out.println("Keys = " + qMap.keys()); |
| 487 | 0 | System.out.println("Values = " + qMap.values()); |
| 488 | ||
| 489 | 0 | Map aMap = new HashMap(); |
| 490 | 0 | for (int i = 0; i < 5; i++) |
| 491 | { |
|
| 492 | 0 | aMap.put(Integer.toString(i), Integer.toString(i)); |
| 493 | } |
|
| 494 | 0 | qMap = new QueueMap( aMap ); |
| 495 | 0 | System.out.println("\nHashMap = " + aMap); |
| 496 | 0 | System.out.println("Map = " + qMap); |
| 497 | 0 | System.out.println("Keys = " + qMap.keys()); |
| 498 | 0 | System.out.println("Values = " + qMap.values()); |
| 499 | ||
| 500 | 0 | qMap = new QueueMap(); |
| 501 | 0 | qMap.put( "Test1", "String1" ); |
| 502 | 0 | qMap.put( "Test2", "String2" ); |
| 503 | 0 | qMap.put( "Test3", "String3" ); |
| 504 | 0 | qMap.put( "Test4", "String4" ); |
| 505 | 0 | qMap.put( "Test5", "String5" ); |
| 506 | 0 | System.out.println("\nStandard Test, Map = " + qMap); |
| 507 | 0 | qMap.put( "Test6", "String6" ); |
| 508 | 0 | qMap.put( "Test7", "String7" ); |
| 509 | 0 | System.out.println("Put New Test, Map = " + qMap); |
| 510 | 0 | qMap.put( "Test2", "New String2" ); |
| 511 | 0 | qMap.put( "Test6", "New String6" ); |
| 512 | 0 | System.out.println("Put Existing Test, Map = " + qMap); |
| 513 | 0 | qMap.put( "Test5", null ); |
| 514 | 0 | qMap.put( "Test8", null ); |
| 515 | 0 | System.out.println("Put Null Test, Map = " + qMap); |
| 516 | 0 | qMap.remove( "Test1" ); |
| 517 | 0 | qMap.remove( "Test3" ); |
| 518 | 0 | qMap.remove( "Test5" ); |
| 519 | 0 | qMap.remove( "Test9" ); |
| 520 | 0 | System.out.println("Remove Test, Map = " + qMap); |
| 521 | 0 | System.out.println(" Keys = " + qMap.keys()); |
| 522 | 0 | System.out.println(" Values = " + qMap.values()); |
| 523 | 0 | qMap.clear(); |
| 524 | 0 | qMap.put( "Test10", "String10" ); |
| 525 | 0 | qMap.put( "Test11", "String11" ); |
| 526 | 0 | qMap.put( "Test12", "String12" ); |
| 527 | 0 | System.out.println("Clear Test, Map = " + qMap); |
| 528 | ||
| 529 | 0 | aMap = new HashMap(); |
| 530 | 0 | aMap.put( "Test10", "String10" ); |
| 531 | 0 | aMap.put( "Test11", "String11" ); |
| 532 | 0 | aMap.put( "Test12", "String12" ); |
| 533 | 0 | System.out.println("Equality Test, Equal = " + qMap.equals( aMap )); |
| 534 | 0 | } |
| 535 | ||
| 536 | } |
|
| 537 | ||
| 538 |