Example usage for org.eclipse.jdt.internal.compiler.lookup ReferenceBinding canBeSeenBy

List of usage examples for org.eclipse.jdt.internal.compiler.lookup ReferenceBinding canBeSeenBy

Introduction

In this page you can find the example usage for org.eclipse.jdt.internal.compiler.lookup ReferenceBinding canBeSeenBy.

Prototype

@Override
public boolean canBeSeenBy(Scope scope) 

Source Link

Document

Answer true if the receiver is visible to the type provided by the scope.

Usage

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public ReferenceBinding findDirectMemberType(char[] typeName, ReferenceBinding enclosingType) {
    if ((enclosingType.tagBits & TagBits.HasNoMemberTypes) != 0)
        return null; // know it has no member types (nor inherited member types)

    ReferenceBinding enclosingReceiverType = enclosingReceiverType();
    CompilationUnitScope unitScope = compilationUnitScope();
    unitScope.recordReference(enclosingType, typeName);
    ReferenceBinding memberType = enclosingType.getMemberType(typeName);
    if (memberType != null) {
        unitScope.recordTypeReference(memberType);
        if (enclosingReceiverType == null) {
            if (memberType.canBeSeenBy(getCurrentPackage())) {
                return memberType;
            }//  w  w w.j a  va 2  s  .  co  m
            // maybe some type in the compilation unit is extending some class in some package
            // and the selection is for some protected inner class of that superclass
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=235658
            if (this instanceof CompilationUnitScope) {
                TypeDeclaration[] types = ((CompilationUnitScope) this).referenceContext.types;
                if (types != null) {
                    for (int i = 0, max = types.length; i < max; i++) {
                        if (memberType.canBeSeenBy(enclosingType, types[i].binding)) {
                            return memberType;
                        }
                    }
                }
            }
        } else if (memberType.canBeSeenBy(enclosingType, enclosingReceiverType)) {
            return memberType;
        }
        return new ProblemReferenceBinding(new char[][] { typeName }, memberType, ProblemReasons.NotVisible);
    }
    return null;
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public FieldBinding findField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite,
        boolean needResolve, boolean invisibleFieldsOk) {

    CompilationUnitScope unitScope = compilationUnitScope();
    unitScope.recordTypeReference(receiverType);

    checkArrayField: {//from   ww w . j ava2 s.c  o m
        TypeBinding leafType;
        switch (receiverType.kind()) {
        case Binding.BASE_TYPE:
            return null;
        case Binding.WILDCARD_TYPE:
        case Binding.INTERSECTION_TYPE:
        case Binding.TYPE_PARAMETER: // capture
            TypeBinding receiverErasure = receiverType.erasure();
            if (!receiverErasure.isArrayType())
                break checkArrayField;
            leafType = receiverErasure.leafComponentType();
            break;
        case Binding.ARRAY_TYPE:
            leafType = receiverType.leafComponentType();
            break;
        default:
            break checkArrayField;
        }
        if (leafType instanceof ReferenceBinding)
            if (!((ReferenceBinding) leafType).canBeSeenBy(this))
                return new ProblemFieldBinding((ReferenceBinding) leafType, fieldName,
                        ProblemReasons.ReceiverTypeNotVisible);
        if (CharOperation.equals(fieldName, TypeConstants.LENGTH)) {
            if ((leafType.tagBits & TagBits.HasMissingType) != 0) {
                return new ProblemFieldBinding(ArrayBinding.ArrayLength, null, fieldName,
                        ProblemReasons.NotFound);
            }
            return ArrayBinding.ArrayLength;
        }
        return null;
    }

    ReferenceBinding currentType = (ReferenceBinding) receiverType;
    if (!currentType.canBeSeenBy(this))
        return new ProblemFieldBinding(currentType, fieldName, ProblemReasons.ReceiverTypeNotVisible);

    currentType.initializeForStaticImports();
    FieldBinding field = currentType.getField(fieldName, needResolve);
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=316456
    boolean insideTypeAnnotations = this instanceof MethodScope && ((MethodScope) this).insideTypeAnnotation;
    if (field != null) {
        if (invisibleFieldsOk) {
            return field;
        }
        if (invocationSite == null || insideTypeAnnotations ? field.canBeSeenBy(getCurrentPackage())
                : field.canBeSeenBy(currentType, invocationSite, this))
            return field;
        return new ProblemFieldBinding(field /* closest match*/, field.declaringClass, fieldName,
                ProblemReasons.NotVisible);
    }
    // collect all superinterfaces of receiverType until the field is found in a supertype
    ReferenceBinding[] interfacesToVisit = null;
    int nextPosition = 0;
    FieldBinding visibleField = null;
    boolean keepLooking = true;
    FieldBinding notVisibleField = null;
    // we could hold onto the not visible field for extra error reporting
    while (keepLooking) {
        ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
        if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
            if (interfacesToVisit == null) {
                interfacesToVisit = itsInterfaces;
                nextPosition = interfacesToVisit.length;
            } else {
                int itsLength = itsInterfaces.length;
                if (nextPosition + itsLength >= interfacesToVisit.length)
                    System.arraycopy(interfacesToVisit, 0,
                            interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0,
                            nextPosition);
                nextInterface: for (int a = 0; a < itsLength; a++) {
                    ReferenceBinding next = itsInterfaces[a];
                    for (int b = 0; b < nextPosition; b++)
                        if (next == interfacesToVisit[b])
                            continue nextInterface;
                    interfacesToVisit[nextPosition++] = next;
                }
            }
        }
        if ((currentType = currentType.superclass()) == null)
            break;

        unitScope.recordTypeReference(currentType);
        currentType.initializeForStaticImports();
        currentType = (ReferenceBinding) currentType.capture(this,
                invocationSite == null ? 0 : invocationSite.sourceEnd());
        if ((field = currentType.getField(fieldName, needResolve)) != null) {
            if (invisibleFieldsOk) {
                return field;
            }
            keepLooking = false;
            if (field.canBeSeenBy(receiverType, invocationSite, this)) {
                if (visibleField == null)
                    visibleField = field;
                else
                    return new ProblemFieldBinding(visibleField /* closest match*/, visibleField.declaringClass,
                            fieldName, ProblemReasons.Ambiguous);
            } else {
                if (notVisibleField == null)
                    notVisibleField = field;
            }
        }
    }

    // walk all visible interfaces to find ambiguous references
    if (interfacesToVisit != null) {
        ProblemFieldBinding ambiguous = null;
        done: for (int i = 0; i < nextPosition; i++) {
            ReferenceBinding anInterface = interfacesToVisit[i];
            unitScope.recordTypeReference(anInterface);
            // no need to capture rcv interface, since member field is going to be static anyway
            if ((field = anInterface.getField(fieldName, true /*resolve*/)) != null) {
                if (invisibleFieldsOk) {
                    return field;
                }
                if (visibleField == null) {
                    visibleField = field;
                } else {
                    ambiguous = new ProblemFieldBinding(visibleField /* closest match*/,
                            visibleField.declaringClass, fieldName, ProblemReasons.Ambiguous);
                    break done;
                }
            } else {
                ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
                if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
                    int itsLength = itsInterfaces.length;
                    if (nextPosition + itsLength >= interfacesToVisit.length)
                        System.arraycopy(interfacesToVisit, 0,
                                interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0,
                                nextPosition);
                    nextInterface: for (int a = 0; a < itsLength; a++) {
                        ReferenceBinding next = itsInterfaces[a];
                        for (int b = 0; b < nextPosition; b++)
                            if (next == interfacesToVisit[b])
                                continue nextInterface;
                        interfacesToVisit[nextPosition++] = next;
                    }
                }
            }
        }
        if (ambiguous != null)
            return ambiguous;
    }

    if (visibleField != null)
        return visibleField;
    if (notVisibleField != null) {
        return new ProblemFieldBinding(notVisibleField, currentType, fieldName, ProblemReasons.NotVisible);
    }
    return null;
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public ReferenceBinding findMemberType(char[] typeName, ReferenceBinding enclosingType) {
    if ((enclosingType.tagBits & TagBits.HasNoMemberTypes) != 0)
        return null; // know it has no member types (nor inherited member types)

    ReferenceBinding enclosingSourceType = enclosingSourceType();
    PackageBinding currentPackage = getCurrentPackage();
    CompilationUnitScope unitScope = compilationUnitScope();
    unitScope.recordReference(enclosingType, typeName);
    ReferenceBinding memberType = enclosingType.getMemberType(typeName);
    if (memberType != null) {
        unitScope.recordTypeReference(memberType);
        if (enclosingSourceType == null || (this.parent == unitScope
                && (enclosingSourceType.tagBits & TagBits.TypeVariablesAreConnected) == 0)
                        ? memberType.canBeSeenBy(currentPackage)
                        : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
            return memberType;
        return new ProblemReferenceBinding(new char[][] { typeName }, memberType, ProblemReasons.NotVisible);
    }//from   w  w w. java2 s.  com

    // collect all superinterfaces of receiverType until the memberType is found in a supertype
    ReferenceBinding currentType = enclosingType;
    ReferenceBinding[] interfacesToVisit = null;
    int nextPosition = 0;
    ReferenceBinding visibleMemberType = null;
    boolean keepLooking = true;
    ReferenceBinding notVisible = null;
    // we could hold onto the not visible field for extra error reporting
    while (keepLooking) {
        ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
        if (itsInterfaces == null) { // needed for statically imported types which don't know their hierarchy yet
            ReferenceBinding sourceType = currentType.isParameterizedType()
                    ? ((ParameterizedTypeBinding) currentType).genericType()
                    : currentType;
            if (sourceType.isHierarchyBeingConnected())
                return null; // looking for an undefined member type in its own superclass ref
            ((SourceTypeBinding) sourceType).scope.connectTypeHierarchy();
            itsInterfaces = currentType.superInterfaces();
        }
        if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
            if (interfacesToVisit == null) {
                interfacesToVisit = itsInterfaces;
                nextPosition = interfacesToVisit.length;
            } else {
                int itsLength = itsInterfaces.length;
                if (nextPosition + itsLength >= interfacesToVisit.length)
                    System.arraycopy(interfacesToVisit, 0,
                            interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0,
                            nextPosition);
                nextInterface: for (int a = 0; a < itsLength; a++) {
                    ReferenceBinding next = itsInterfaces[a];
                    for (int b = 0; b < nextPosition; b++)
                        if (next == interfacesToVisit[b])
                            continue nextInterface;
                    interfacesToVisit[nextPosition++] = next;
                }
            }
        }
        if ((currentType = currentType.superclass()) == null)
            break;

        unitScope.recordReference(currentType, typeName);
        if ((memberType = currentType.getMemberType(typeName)) != null) {
            unitScope.recordTypeReference(memberType);
            keepLooking = false;
            if (enclosingSourceType == null ? memberType.canBeSeenBy(currentPackage)
                    : memberType.canBeSeenBy(enclosingType, enclosingSourceType)) {
                if (visibleMemberType == null)
                    visibleMemberType = memberType;
                else
                    return new ProblemReferenceBinding(new char[][] { typeName }, visibleMemberType,
                            ProblemReasons.Ambiguous);
            } else {
                notVisible = memberType;
            }
        }
    }
    // walk all visible interfaces to find ambiguous references
    if (interfacesToVisit != null) {
        ProblemReferenceBinding ambiguous = null;
        done: for (int i = 0; i < nextPosition; i++) {
            ReferenceBinding anInterface = interfacesToVisit[i];
            unitScope.recordReference(anInterface, typeName);
            if ((memberType = anInterface.getMemberType(typeName)) != null) {
                unitScope.recordTypeReference(memberType);
                if (visibleMemberType == null) {
                    visibleMemberType = memberType;
                } else {
                    ambiguous = new ProblemReferenceBinding(new char[][] { typeName }, visibleMemberType,
                            ProblemReasons.Ambiguous);
                    break done;
                }
            } else {
                ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
                if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
                    int itsLength = itsInterfaces.length;
                    if (nextPosition + itsLength >= interfacesToVisit.length)
                        System.arraycopy(interfacesToVisit, 0,
                                interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0,
                                nextPosition);
                    nextInterface: for (int a = 0; a < itsLength; a++) {
                        ReferenceBinding next = itsInterfaces[a];
                        for (int b = 0; b < nextPosition; b++)
                            if (next == interfacesToVisit[b])
                                continue nextInterface;
                        interfacesToVisit[nextPosition++] = next;
                    }
                }
            }
        }
        if (ambiguous != null)
            return ambiguous;
    }
    if (visibleMemberType != null)
        return visibleMemberType;
    if (notVisible != null)
        return new ProblemReferenceBinding(new char[][] { typeName }, notVisible, ProblemReasons.NotVisible);
    return null;
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public ReferenceBinding findType(char[] typeName, PackageBinding declarationPackage,
        PackageBinding invocationPackage) {

    compilationUnitScope().recordReference(declarationPackage.compoundName, typeName);
    ReferenceBinding typeBinding = declarationPackage.getType(typeName);
    if (typeBinding == null)
        return null;

    if (typeBinding.isValidBinding()) {
        if (declarationPackage != invocationPackage && !typeBinding.canBeSeenBy(invocationPackage))
            return new ProblemReferenceBinding(new char[][] { typeName }, typeBinding,
                    ProblemReasons.NotVisible);
    }/*from w  w  w  .  ja v  a  2s  . co  m*/
    return typeBinding;
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public MethodBinding getMethod(TypeBinding receiverType, char[] selector, TypeBinding[] argumentTypes,
        InvocationSite invocationSite) {
    CompilationUnitScope unitScope = compilationUnitScope();
    LookupEnvironment env = unitScope.environment;
    try {/*www . j  a va  2  s .  c  o m*/
        env.missingClassFileLocation = invocationSite;
        switch (receiverType.kind()) {
        case Binding.BASE_TYPE:
            return new ProblemMethodBinding(selector, argumentTypes, ProblemReasons.NotFound);
        case Binding.ARRAY_TYPE:
            unitScope.recordTypeReference(receiverType);
            return findMethodForArray((ArrayBinding) receiverType, selector, argumentTypes, invocationSite);
        }
        unitScope.recordTypeReference(receiverType);

        ReferenceBinding currentType = (ReferenceBinding) receiverType;
        if (!currentType.canBeSeenBy(this))
            return new ProblemMethodBinding(selector, argumentTypes, ProblemReasons.ReceiverTypeNotVisible);

        // retrieve an exact visible match (if possible)
        MethodBinding methodBinding = findExactMethod(currentType, selector, argumentTypes, invocationSite);
        if (methodBinding != null)
            return methodBinding;

        methodBinding = findMethod(currentType, selector, argumentTypes, invocationSite);
        // GROOVY start: give it one more chance as the ast transform may have introduced it
        // is this the right approach?  Requires ast transforms running before this is done
        if (methodBinding == null) {
            methodBinding = oneLastLook(currentType, selector, argumentTypes, invocationSite);
        }
        // GROOVY end
        if (methodBinding == null)
            return new ProblemMethodBinding(selector, argumentTypes, ProblemReasons.NotFound);
        if (!methodBinding.isValidBinding())
            return methodBinding;

        // special treatment for Object.getClass() in 1.5 mode (substitute parameterized return type)
        if (argumentTypes == Binding.NO_PARAMETERS && CharOperation.equals(selector, TypeConstants.GETCLASS)
                && methodBinding.returnType.isParameterizedType()/*1.5*/) {
            return environment().createGetClassMethod(receiverType, methodBinding, this);
        }
        return methodBinding;
    } catch (AbortCompilation e) {
        e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
        throw e;
    } finally {
        env.missingClassFileLocation = null;
    }
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public final TypeBinding getType(char[] name, PackageBinding packageBinding) {
    if (packageBinding == null)
        return getType(name);

    Binding binding = packageBinding.getTypeOrPackage(name);
    if (binding == null) {
        return new ProblemReferenceBinding(CharOperation.arrayConcat(packageBinding.compoundName, name), null,
                ProblemReasons.NotFound);
    }/*www.j  a  v a  2s .  co m*/
    if (!binding.isValidBinding()) {
        return new ProblemReferenceBinding(
                binding instanceof ReferenceBinding ? ((ReferenceBinding) binding).compoundName
                        : CharOperation.arrayConcat(packageBinding.compoundName, name),
                binding instanceof ReferenceBinding
                        ? (ReferenceBinding) ((ReferenceBinding) binding).closestMatch()
                        : null,
                binding.problemId());
    }
    ReferenceBinding typeBinding = (ReferenceBinding) binding;
    if (!typeBinding.canBeSeenBy(this))
        return new ProblemReferenceBinding(typeBinding.compoundName, typeBinding, ProblemReasons.NotVisible);
    return typeBinding;
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public final TypeBinding getType(char[][] compoundName, int typeNameLength) {
    if (typeNameLength == 1) {
        // Would like to remove this test and require senders to specially handle base types
        TypeBinding binding = getBaseType(compoundName[0]);
        if (binding != null)
            return binding;
    }/*  ww  w  . j  av  a  2s.co m*/

    CompilationUnitScope unitScope = compilationUnitScope();
    unitScope.recordQualifiedReference(compoundName);
    Binding binding = getTypeOrPackage(compoundName[0],
            typeNameLength == 1 ? Binding.TYPE : Binding.TYPE | Binding.PACKAGE, true);
    if (binding == null) {
        char[][] qName = new char[][] { compoundName[0] };
        return new ProblemReferenceBinding(qName,
                environment().createMissingType(compilationUnitScope().getCurrentPackage(), qName),
                ProblemReasons.NotFound);
    }
    if (!binding.isValidBinding()) {
        if (binding instanceof PackageBinding) {
            char[][] qName = new char[][] { compoundName[0] };
            return new ProblemReferenceBinding(qName, environment().createMissingType(null, qName),
                    ProblemReasons.NotFound);
        }
        return (ReferenceBinding) binding;
    }
    int currentIndex = 1;
    boolean checkVisibility = false;
    if (binding instanceof PackageBinding) {
        PackageBinding packageBinding = (PackageBinding) binding;
        while (currentIndex < typeNameLength) {
            binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); // does not check visibility
            if (binding == null) {
                char[][] qName = CharOperation.subarray(compoundName, 0, currentIndex);
                return new ProblemReferenceBinding(qName,
                        environment().createMissingType(packageBinding, qName), ProblemReasons.NotFound);
            }
            if (!binding.isValidBinding())
                return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex),
                        binding instanceof ReferenceBinding
                                ? (ReferenceBinding) ((ReferenceBinding) binding).closestMatch()
                                : null,
                        binding.problemId());
            if (!(binding instanceof PackageBinding))
                break;
            packageBinding = (PackageBinding) binding;
        }
        if (binding instanceof PackageBinding) {
            char[][] qName = CharOperation.subarray(compoundName, 0, currentIndex);
            return new ProblemReferenceBinding(qName, environment().createMissingType(null, qName),
                    ProblemReasons.NotFound);
        }
        checkVisibility = true;
    }

    // binding is now a ReferenceBinding
    ReferenceBinding typeBinding = (ReferenceBinding) binding;
    unitScope.recordTypeReference(typeBinding);
    if (checkVisibility) // handles the fall through case
        if (!typeBinding.canBeSeenBy(this))
            return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex),
                    typeBinding, ProblemReasons.NotVisible);

    while (currentIndex < typeNameLength) {
        typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
        if (!typeBinding.isValidBinding()) {
            if (typeBinding instanceof ProblemReferenceBinding) {
                ProblemReferenceBinding problemBinding = (ProblemReferenceBinding) typeBinding;
                return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex),
                        problemBinding.closestReferenceMatch(), typeBinding.problemId());
            }
            return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex),
                    (ReferenceBinding) ((ReferenceBinding) binding).closestMatch(), typeBinding.problemId());
        }
    }
    return typeBinding;
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public final Binding getTypeOrPackage(char[][] compoundName) {
    int nameLength = compoundName.length;
    if (nameLength == 1) {
        TypeBinding binding = getBaseType(compoundName[0]);
        if (binding != null)
            return binding;
    }/*from w  w  w  .  jav a  2  s. c o  m*/
    Binding binding = getTypeOrPackage(compoundName[0], Binding.TYPE | Binding.PACKAGE, true);
    if (!binding.isValidBinding())
        return binding;

    int currentIndex = 1;
    boolean checkVisibility = false;
    if (binding instanceof PackageBinding) {
        PackageBinding packageBinding = (PackageBinding) binding;

        while (currentIndex < nameLength) {
            binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
            if (binding == null)
                return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), null,
                        ProblemReasons.NotFound);
            if (!binding.isValidBinding())
                return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex),
                        binding instanceof ReferenceBinding
                                ? (ReferenceBinding) ((ReferenceBinding) binding).closestMatch()
                                : null,
                        binding.problemId());
            if (!(binding instanceof PackageBinding))
                break;
            packageBinding = (PackageBinding) binding;
        }
        if (binding instanceof PackageBinding)
            return binding;
        checkVisibility = true;
    }
    // binding is now a ReferenceBinding
    ReferenceBinding typeBinding = (ReferenceBinding) binding;
    ReferenceBinding qualifiedType = (ReferenceBinding) environment().convertToRawType(typeBinding,
            false /*do not force conversion of enclosing types*/);

    if (checkVisibility) // handles the fall through case
        if (!typeBinding.canBeSeenBy(this))
            return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex),
                    typeBinding, ProblemReasons.NotVisible);

    while (currentIndex < nameLength) {
        typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
        // checks visibility
        if (!typeBinding.isValidBinding())
            return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex),
                    (ReferenceBinding) typeBinding.closestMatch(), typeBinding.problemId());

        if (typeBinding.isGenericType()) {
            qualifiedType = environment().createRawType(typeBinding, qualifiedType);
        } else {
            qualifiedType = (qualifiedType != null
                    && (qualifiedType.isRawType() || qualifiedType.isParameterizedType()))
                            ? environment().createParameterizedType(typeBinding, null, qualifiedType)
                            : typeBinding;
        }
    }
    return qualifiedType;
}