1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/* 2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project 3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License"); 5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License. 6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at 7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * http://www.apache.org/licenses/LICENSE-2.0 9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software 11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS, 12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and 14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License. 15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.rop.annotation; 18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.Constant; 20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstAnnotation; 21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstFieldRef; 22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstLiteralBits; 23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstMethodRef; 24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstNat; 25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstType; 26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstUtf8; 27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.TypedConstant; 28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.Hex; 29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.MutabilityControl; 30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.ToHuman; 31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Collection; 33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Collections; 34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Iterator; 35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.TreeMap; 36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/** 38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * An annotation on an element of a class. Annotations have an 39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * associated type and additionally consist of a set of (name, value) 40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * pairs, where the names are unique. 41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class Annotation extends MutabilityControl 43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul implements Comparable<Annotation>, ToHuman { 44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@code non-null;} type of the annotation */ 45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private final CstType type; 46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@code non-null;} the visibility of the annotation */ 48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private final AnnotationVisibility visibility; 49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@code non-null;} map from names to {@link NameValuePair} instances */ 51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private final TreeMap<CstUtf8, NameValuePair> elements; 52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Construct an instance. It initially contains no elements. 55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param type {@code non-null;} type of the annotation 57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param visibility {@code non-null;} the visibility of the annotation 58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public Annotation(CstType type, AnnotationVisibility visibility) { 60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (type == null) { 61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new NullPointerException("type == null"); 62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (visibility == null) { 65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new NullPointerException("visibility == null"); 66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.type = type; 69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.visibility = visibility; 70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.elements = new TreeMap<CstUtf8, NameValuePair>(); 71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul @Override 75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public boolean equals(Object other) { 76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (! (other instanceof Annotation)) { 77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return false; 78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Annotation otherAnnotation = (Annotation) other; 81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (! (type.equals(otherAnnotation.type) 83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul && (visibility == otherAnnotation.visibility))) { 84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return false; 85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return elements.equals(otherAnnotation.elements); 88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public int hashCode() { 92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int hash = type.hashCode(); 93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul hash = (hash * 31) + elements.hashCode(); 94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul hash = (hash * 31) + visibility.hashCode(); 95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return hash; 96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public int compareTo(Annotation other) { 100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int result = type.compareTo(other.type); 101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (result != 0) { 103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return result; 104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result = visibility.compareTo(other.visibility); 107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (result != 0) { 109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return result; 110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Iterator<NameValuePair> thisIter = elements.values().iterator(); 113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Iterator<NameValuePair> otherIter = other.elements.values().iterator(); 114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul while (thisIter.hasNext() && otherIter.hasNext()) { 116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul NameValuePair thisOne = thisIter.next(); 117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul NameValuePair otherOne = otherIter.next(); 118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result = thisOne.compareTo(otherOne); 120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (result != 0) { 121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return result; 122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (thisIter.hasNext()) { 126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return 1; 127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } else if (otherIter.hasNext()) { 128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return -1; 129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return 0; 132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul @Override 136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public String toString() { 137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return toHuman(); 138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public String toHuman() { 142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul StringBuilder sb = new StringBuilder(); 143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul sb.append(visibility.toHuman()); 145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul sb.append("-annotation "); 146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul sb.append(type.toHuman()); 147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul sb.append(" {"); 148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul boolean first = true; 150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (NameValuePair pair : elements.values()) { 151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (first) { 152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul first = false; 153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } else { 154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul sb.append(", "); 155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul sb.append(pair.getName().toHuman()); 157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul sb.append(": "); 158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul sb.append(pair.getValue().toHuman()); 159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul sb.append("}"); 162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return sb.toString(); 163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Gets the type of this instance. 167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code non-null;} the type 169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public CstType getType() { 171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return type; 172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Gets the visibility of this instance. 176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code non-null;} the visibility 178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public AnnotationVisibility getVisibility() { 180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return visibility; 181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Put an element into the set of (name, value) pairs for this instance. 185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * If there is a preexisting element with the same name, it will be 186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * replaced by this method. 187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param pair {@code non-null;} the (name, value) pair to place into this instance 189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void put(NameValuePair pair) { 191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throwIfImmutable(); 192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (pair == null) { 194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new NullPointerException("pair == null"); 195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul elements.put(pair.getName(), pair); 198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Add an element to the set of (name, value) pairs for this instance. 202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * It is an error to call this method if there is a preexisting element 203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * with the same name. 204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param pair {@code non-null;} the (name, value) pair to add to this instance 206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void add(NameValuePair pair) { 208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throwIfImmutable(); 209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (pair == null) { 211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new NullPointerException("pair == null"); 212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul CstUtf8 name = pair.getName(); 215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (elements.get(name) != null) { 217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new IllegalArgumentException("name already added: " + name); 218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul elements.put(name, pair); 221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Gets the set of name-value pairs contained in this instance. The 225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * result is always unmodifiable. 226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code non-null;} the set of name-value pairs 228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public Collection<NameValuePair> getNameValuePairs() { 230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return Collections.unmodifiableCollection(elements.values()); 231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul} 233