11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2010 The Guava Authors 31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License. 61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at 71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and 141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License. 151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.collect.testing; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.Serializable; 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collection; 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Comparator; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Iterator; 233ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffinimport java.util.NavigableSet; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.SortedSet; 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.TreeSet; 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A wrapper around {@code TreeSet} that aggressively checks to see if elements 291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * are mutually comparable. This implementation passes the navigable set test 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * suites. 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Louis Wasserman 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 343ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffinpublic final class SafeTreeSet<E> implements Serializable, NavigableSet<E> { 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @SuppressWarnings("unchecked") 360888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final Comparator<Object> NATURAL_ORDER = new Comparator<Object>() { 370888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public int compare(Object o1, Object o2) { 380888a09821a98ac0680fad765217302858e70fa4Paul Duffin return ((Comparable<Object>) o1).compareTo(o2); 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 413ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin private final NavigableSet<E> delegate; 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public SafeTreeSet() { 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this(new TreeSet<E>()); 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public SafeTreeSet(Collection<? extends E> collection) { 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this(new TreeSet<E>(collection)); 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public SafeTreeSet(Comparator<? super E> comparator) { 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this(new TreeSet<E>(comparator)); 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 553ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin public SafeTreeSet(SortedSet<E> set) { 563ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin this(new TreeSet<E>(set)); 573ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 583ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 593ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin private SafeTreeSet(NavigableSet<E> delegate) { 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.delegate = delegate; 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (E e : this) { 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert checkValid(e); 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public boolean add(E element) { 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.add(checkValid(element)); 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public boolean addAll(Collection<? extends E> collection) { 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (E e : collection) { 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert checkValid(e); 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.addAll(collection); 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 773ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public E ceiling(E e) { 783ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return delegate.ceiling(checkValid(e)); 793ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 803ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void clear() { 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert delegate.clear(); 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @SuppressWarnings("unchecked") 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public Comparator<? super E> comparator() { 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Comparator<? super E> comparator = delegate.comparator(); 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (comparator == null) { 890888a09821a98ac0680fad765217302858e70fa4Paul Duffin comparator = (Comparator<? super E>) NATURAL_ORDER; 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return comparator; 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public boolean contains(Object object) { 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.contains(checkValid(object)); 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public boolean containsAll(Collection<?> c) { 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.containsAll(c); 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1023ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public Iterator<E> descendingIterator() { 1033ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return delegate.descendingIterator(); 1043ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1053ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 1063ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public NavigableSet<E> descendingSet() { 1073ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return new SafeTreeSet<E>(delegate.descendingSet()); 1083ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1093ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public E first() { 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.first(); 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1143ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public E floor(E e) { 1153ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return delegate.floor(checkValid(e)); 1163ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1173ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public SortedSet<E> headSet(E toElement) { 1193ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return headSet(toElement, false); 1203ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1213ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 1223ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public NavigableSet<E> headSet(E toElement, boolean inclusive) { 1233ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return new SafeTreeSet<E>( 1243ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin delegate.headSet(checkValid(toElement), inclusive)); 1253ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1263ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 1273ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public E higher(E e) { 1283ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return delegate.higher(checkValid(e)); 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public boolean isEmpty() { 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.isEmpty(); 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public Iterator<E> iterator() { 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.iterator(); 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public E last() { 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.last(); 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1433ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public E lower(E e) { 1443ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return delegate.lower(checkValid(e)); 1453ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1463ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 1473ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public E pollFirst() { 1483ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return delegate.pollFirst(); 1493ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1503ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 1513ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public E pollLast() { 1523ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return delegate.pollLast(); 1533ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1543ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public boolean remove(Object object) { 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.remove(checkValid(object)); 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public boolean removeAll(Collection<?> c) { 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.removeAll(c); 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public boolean retainAll(Collection<?> c) { 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.retainAll(c); 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public int size() { 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.size(); 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1713ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public NavigableSet<E> subSet( 1723ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { 1733ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return new SafeTreeSet<E>( 1743ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin delegate.subSet(checkValid(fromElement), fromInclusive, 1753ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin checkValid(toElement), toInclusive)); 1763ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public SortedSet<E> subSet(E fromElement, E toElement) { 1793ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return subSet(fromElement, true, toElement, false); 1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public SortedSet<E> tailSet(E fromElement) { 1833ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return tailSet(fromElement, true); 1843ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 1853ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 1863ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin @Override public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { 1873ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin return new SafeTreeSet<E>(delegate.tailSet(checkValid(fromElement), inclusive)); 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public Object[] toArray() { 1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.toArray(); 1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public <T> T[] toArray(T[] a) { 1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.toArray(a); 1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private <T> T checkValid(T t) { 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // a ClassCastException is what's supposed to happen! 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @SuppressWarnings("unchecked") 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert E e = (E) t; 2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert comparator().compare(e, e); 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return t; 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public boolean equals(Object obj) { 2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.equals(obj); 2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public int hashCode() { 2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.hashCode(); 2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public String toString() { 2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.toString(); 2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final long serialVersionUID = 0L; 2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 220