List of usage examples for org.eclipse.jdt.core IBuffer getLength
public int getLength();
From source file:com.android.ide.eclipse.adt.internal.build.ConvertSwitchQuickFixProcessor.java
License:Open Source License
@Override public IJavaCompletionProposal[] getCorrections(IInvocationContext context, IProblemLocation[] location) throws CoreException { if (location == null || location.length == 0) { return null; }/*from www. jav a2 s . c o m*/ ASTNode coveringNode = context.getCoveringNode(); if (coveringNode == null) { return null; } // Look up the fully qualified name of the non-constant expression, if any, and // make sure it's R-something. if (coveringNode.getNodeType() == ASTNode.SIMPLE_NAME) { coveringNode = coveringNode.getParent(); if (coveringNode == null) { return null; } } if (coveringNode.getNodeType() != ASTNode.QUALIFIED_NAME) { return null; } QualifiedName name = (QualifiedName) coveringNode; if (!name.getFullyQualifiedName().startsWith("R.")) { //$NON-NLS-1$ return null; } IProblemLocation error = location[0]; int errorStart = error.getOffset(); int errorLength = error.getLength(); int caret = context.getSelectionOffset(); // Even though the hasCorrections() method above will return false for everything // other than non-constant expression errors, it turns out this getCorrections() // method will ALSO be called on lines where there is no such error. In particular, // if you have an invalid cast expression like this: // Button button = findViewById(R.id.textView); // then this method will be called, and the expression will pass all of the above // checks. However, we -don't- want to show a migrate code suggestion in that case! // Therefore, we'll need to check if we're *actually* on a line with the given // problem. // // Unfortunately, we don't get passed the problemId again, and there's no access // to it. So instead we'll need to look up the markers on the line, and see // if we actually have a constant expression warning. This is not pretty!! boolean foundError = false; ICompilationUnit compilationUnit = context.getCompilationUnit(); IResource file = compilationUnit.getResource(); if (file != null) { IDocumentProvider provider = new TextFileDocumentProvider(); try { provider.connect(file); IDocument document = provider.getDocument(file); if (document != null) { List<IMarker> markers = AdtUtils.findMarkersOnLine(IMarker.PROBLEM, file, document, errorStart); for (IMarker marker : markers) { String message = marker.getAttribute(IMarker.MESSAGE, ""); // There are no other attributes in the marker we can use to identify // the exact error, so we'll need to resort to the actual message // text even though that would not work if the messages had been // localized... This can also break if the error messages change. Yuck. if (message.contains("constant expressions")) { //$NON-NLS-1$ foundError = true; } } } } catch (Exception e) { AdtPlugin.log(e, "Can't validate error message in %1$s", file.getName()); } finally { provider.disconnect(file); } } if (!foundError) { // Not a constant-expression warning, so do nothing return null; } IBuffer buffer = compilationUnit.getBuffer(); boolean sameLine = false; // See if the caret is on the same line as the error if (caret <= errorStart) { // Search backwards to beginning of line for (int i = errorStart; i >= 0; i--) { if (i <= caret) { sameLine = true; break; } char c = buffer.getChar(i); if (c == '\n') { break; } } } else { // Search forwards to the end of the line for (int i = errorStart + errorLength, n = buffer.getLength(); i < n; i++) { if (i >= caret) { sameLine = true; break; } char c = buffer.getChar(i); if (c == '\n') { break; } } } if (sameLine) { String expression = buffer.getText(errorStart, errorLength); return new IJavaCompletionProposal[] { new MigrateProposal(expression) }; } return null; }
From source file:com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringProposal.java
License:Open Source License
@Override public String getAdditionalProposalInfo() { try {//from w ww. j a va 2s .c o m ASTNode coveringNode = mContext.getCoveringNode(); int start = coveringNode.getStartPosition(); int length = coveringNode.getLength(); IBuffer buffer = mContext.getCompilationUnit().getBuffer(); StringBuilder sb = new StringBuilder(); String string = buffer.getText(start, length); string = ExtractStringRefactoring.unquoteAttrValue(string); String token = ExtractStringInputPage.guessId(string); // Look up the beginning and the end of the line (outside of the extracted string) // such that we can show a preview of the diff, e.g. if you have // foo.setTitle("Hello"); we want to show foo.setTitle(R.string.hello); // so we need to extract "foo.setTitle(" and ");". // Look backwards to the beginning of the line (and strip whitespace) int i = start - 1; while (i > 0) { char c = buffer.getChar(i); if (c == '\r' || (c == '\n')) { break; } i--; } String linePrefix = buffer.getText(i + 1, start - (i + 1)).trim(); // Look forwards to the end of the line (and strip whitespace) i = start + length; while (i < buffer.getLength()) { char c = buffer.getChar(i); if (c == '\r' || (c == '\n')) { break; } i++; } String lineSuffix = buffer.getText(start + length, i - (start + length)); // Should we show the replacement as just R.string.foo or // context.getString(R.string.foo) ? boolean useContext = false; ASTNode parent = coveringNode.getParent(); if (parent != null) { int type = parent.getNodeType(); if (type == ASTNode.ASSIGNMENT || type == ASTNode.VARIABLE_DECLARATION_STATEMENT || type == ASTNode.VARIABLE_DECLARATION_FRAGMENT || type == ASTNode.VARIABLE_DECLARATION_EXPRESSION) { useContext = true; } } // Display .java change: sb.append("...<br>"); //$NON-NLS-1$ sb.append(linePrefix); sb.append("<b>"); //$NON-NLS-1$ if (useContext) { sb.append("context.getString("); //$NON-NLS-1$ } sb.append("R.string."); //$NON-NLS-1$ sb.append(token); if (useContext) { sb.append(")"); //$NON-NLS-1$ } sb.append("</b>"); //$NON-NLS-1$ sb.append(lineSuffix); sb.append("<br>...<br>"); //$NON-NLS-1$ // Display strings.xml change: sb.append("<br>"); //$NON-NLS-1$ sb.append("<resources><br>"); //$NON-NLS-1$ sb.append(" <b><string name=\""); //$NON-NLS-1$ sb.append(token); sb.append("\">"); //$NON-NLS-1$ sb.append(string); sb.append("</string></b><br>"); //$NON-NLS-1$ sb.append("</resources>"); //$NON-NLS-1$ return sb.toString(); } catch (JavaModelException e) { AdtPlugin.log(e, null); } return "Initiates the Extract String refactoring operation"; }
From source file:com.iw.plugins.spindle.ui.wizards.factories.ClassFactory.java
License:Mozilla Public License
/** * Examines a string and returns the first line delimiter found. *///from w w w . j a va2 s .co m public static String getLineDelimiterUsed(IJavaElement elem) throws JavaModelException { ICompilationUnit cu = (ICompilationUnit) elem.getAncestor(IJavaElement.COMPILATION_UNIT); if (cu != null && cu.exists()) { IBuffer buf = cu.getBuffer(); int length = buf.getLength(); for (int i = 0; i < length; i++) { char ch = buf.getChar(i); if (ch == SWT.CR) { if (i + 1 < length) { if (buf.getChar(i + 1) == SWT.LF) { return "\r\n"; //$NON-NLS-1$ } } return "\r"; //$NON-NLS-1$ } else if (ch == SWT.LF) { return "\n"; //$NON-NLS-1$ } } } return System.getProperty("line.separator", "\n"); }
From source file:edu.uci.ics.sourcerer.tools.java.extractor.eclipse.EclipseExtractor.java
License:Open Source License
public boolean extractClassFiles(Collection<IClassFile> classFiles) { TaskProgressLogger task = TaskProgressLogger.get(); task.start("Extracting " + classFiles.size() + " class files", "class files extracted", 500); boolean oneWithSource = false; Map<String, Collection<IClassFile>> memberMap = new HashMap<>(); ;//from ww w . ja v a2s.com Set<String> sourceFailed = new HashSet<>(); Collection<IClassFile> parentTypes = new LinkedList<>(); for (IClassFile classFile : classFiles) { IType type = classFile.getType(); try { if (type.isMember() || type.isAnonymous() || type.isLocal()) { String key = null; IType dec = type.getDeclaringType(); if (dec == null) { key = classFile.getElementName(); int dollar = key.indexOf('$'); if (dollar == -1) { if (classFile.getSource() == null) { // Doesn't matter, just make it a parentType parentTypes.add(classFile); } else { logger.log(Level.SEVERE, "Should have a dollar: " + key); } } else { key = key.substring(0, dollar) + ".class"; } } else { key = dec.getClassFile().getElementName(); } if (key != null) { Collection<IClassFile> members = memberMap.get(key); if (members == null) { members = new LinkedList<>(); memberMap.put(key, members); } members.add(classFile); } } else { parentTypes.add(classFile); } } catch (Exception e) { logger.log(Level.SEVERE, classFile.getType().getFullyQualifiedName(), e); sourceFailed.add(classFile.getType().getFullyQualifiedName()); extractClassFile(classFile); } } for (IClassFile classFile : parentTypes) { task.progress(); try { IBuffer buffer = classFile.getBuffer(); if (buffer == null || buffer.getLength() == 0) { extractClassFile(classFile); sourceFailed.add(classFile.getType().getFullyQualifiedName()); } else { IType type = classFile.getType(); // Handle Eclipse issue with GSSUtil if ("sun.security.jgss.GSSUtil".equals(type.getFullyQualifiedName())) { extractClassFile(classFile); sourceFailed.add(classFile.getType().getFullyQualifiedName()); continue; } // Handle multiple top-level types { BinaryType bType = (BinaryType) type; String sourceFile = type.getPackageFragment().getElementName() + "." + bType.getSourceFileName(null); String fqn = classFile.getType().getFullyQualifiedName() + ".java"; if (!fqn.equals(sourceFile)) { continue; } } parser.setStatementsRecovery(true); parser.setResolveBindings(true); parser.setBindingsRecovery(true); parser.setSource(classFile); CompilationUnit unit = (CompilationUnit) parser.createAST(null); boolean foundProblem = false; // start by checking for a "public type" error // just skip this unit in if one is found for (IProblem problem : unit.getProblems()) { if (problem.isError() && problem.getID() == IProblem.PublicClassMustMatchFileName) { foundProblem = true; } } if (foundProblem) { logger.log(Level.WARNING, "Giving up on " + classFile.getElementName()); continue; } boolean trouble = checkForMissingTypes(unit); if (trouble) { sourceFailed.add(classFile.getType().getFullyQualifiedName()); extractClassFile(classFile); } else { try { visitor.setCompilationUnitSource(classFile.getSource()); visitor.setAdvisor( NamingAdvisor.create(classFile, memberMap.get(classFile.getElementName()))); unit.accept(visitor); oneWithSource = true; } catch (Exception e) { logger.log(Level.SEVERE, "Error in extracting " + classFile.getElementName(), e); // for (IProblem problem : unit.getProblems()) { // if (problem.isError()) { // logger.log(Level.SEVERE, "Error in source for class file (" + classFile.getElementName() + "): " + problem.getMessage()); // } // } sourceFailed.add(classFile.getType().getFullyQualifiedName()); extractClassFile(classFile); } } } } catch (JavaModelException | ClassCastException | IllegalArgumentException | NullPointerException e) { logger.log(Level.SEVERE, classFile.getElementName(), e); sourceFailed.add(classFile.getType().getFullyQualifiedName()); extractClassFile(classFile); } } for (String failed : sourceFailed) { Collection<IClassFile> members = memberMap.get(failed); if (members != null) { for (IClassFile classFile : members) { extractClassFile(classFile); } } } task.finish(); return oneWithSource; }
From source file:net.sf.commonclipse.CompareToGenerator.java
License:Apache License
/** * Adds "implements Comparable" to class declaration. * @param type IType//from w w w. ja v a 2s. c o m * @throws JavaModelException model exception */ private void addImplementsComparable(IType type) throws JavaModelException { // does class already implements comparable? IType[] interfaces = type.newSupertypeHierarchy(null).getAllInterfaces(); for (int j = 0, size = interfaces.length; j < size; j++) { if (interfaces[j].getFullyQualifiedName().equals("java.lang.Comparable")) //$NON-NLS-1$ { return; } } // find class declaration ISourceRange nameRange = type.getNameRange(); // no declaration?? if (nameRange == null) { return; } // offset for END of class name int offset = nameRange.getOffset() + nameRange.getLength(); IBuffer buffer = type.getCompilationUnit().getBuffer(); String contents = buffer.getText(offset, buffer.getLength() - offset); // warning, this doesn't handle "implements" and "{" contained in comments in the middle of the declaration! int indexOfPar = contents.indexOf("{"); //$NON-NLS-1$ contents = contents.substring(0, indexOfPar); int indexOfImplements = contents.indexOf("implements"); //$NON-NLS-1$ if (indexOfImplements > -1) { buffer.replace(offset + indexOfImplements + "implements".length()//$NON-NLS-1$ , 0, " Comparable,"); //$NON-NLS-1$ } else { buffer.replace(offset, 0, " implements Comparable"); //$NON-NLS-1$ } buffer.save(null, false); buffer.close(); }
From source file:net.sf.guavaeclipse.creator.CompareMethodCreator.java
License:Apache License
private void addImplementsComparable(IType type) throws JavaModelException { // does class already implements comparable? IType[] interfaces = type.newSupertypeHierarchy(null).getAllInterfaces(); for (int j = 0, size = interfaces.length; j < size; j++) { if (interfaces[j].getFullyQualifiedName().equals("java.lang.Comparable")) //$NON-NLS-1$ {//from ww w .j a va 2 s . c o m return; } } // find class declaration ISourceRange nameRange = type.getNameRange(); // no declaration?? if (nameRange == null) { return; } // offset for END of class name int offset = nameRange.getOffset() + nameRange.getLength(); IBuffer buffer = type.getCompilationUnit().getBuffer(); String contents = buffer.getText(offset, buffer.getLength() - offset); // warning, this doesn't handle "implements" and "{" contained in // comments in the middle of the declaration! int indexOfPar = contents.indexOf("{"); //$NON-NLS-1$ contents = contents.substring(0, indexOfPar); int indexOfImplements = contents.indexOf("implements"); //$NON-NLS-1$ if (indexOfImplements > -1) { buffer.replace(offset + indexOfImplements + "implements".length()//$NON-NLS-1$ , 0, " Comparable<" + type.getElementName() + ">,"); //$NON-NLS-1$ } else { buffer.replace(offset, 0, " implements Comparable<" + type.getElementName() + ">"); //$NON-NLS-1$ } buffer.save(null, false); buffer.close(); }
From source file:org.eclipse.ajdt.core.javaelements.AJCompilationUnit.java
License:Open Source License
/** * this method is a copy of {@link Openable#codeComplete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit, int, CompletionRequestor, WorkingCopyOwner, ITypeRoot)} * The only change is that we need to create an {@link ITDAwareNameEnvironment}, not standard {@link SearchableEnvironment}. * //from w ww . j a va2s . c o m * @param cu * @param unitToSkip * @param position * @param requestor * @param owner * @param typeRoot * @throws JavaModelException */ private void internalCodeComplete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu, org.eclipse.jdt.internal.compiler.env.ICompilationUnit unitToSkip, int position, CompletionRequestor requestor, WorkingCopyOwner owner, ITypeRoot typeRoot, /* AJDT 1.7 */ IProgressMonitor monitor) throws JavaModelException { if (requestor == null) { throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$ } PerformanceStats performanceStats = CompletionEngine.PERF ? PerformanceStats.getStats(JavaModelManager.COMPLETION_PERF, this) : null; if (performanceStats != null) { performanceStats.startRun(new String(cu.getFileName()) + " at " + position); //$NON-NLS-1$ } IBuffer buffer = getBuffer(); if (buffer == null) { return; } if (position < -1 || position > buffer.getLength()) { throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS)); } JavaProject project = (JavaProject) getJavaProject(); /* AJDT 1.7 */ ITDAwareNameEnvironment environment = new ITDAwareNameEnvironment(project, owner, monitor); environment.setUnitToSkip(unitToSkip); // code complete /* AJDT 1.7 */ CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project, owner, monitor); engine.complete(cu, position, 0, typeRoot); if (performanceStats != null) { performanceStats.endRun(); } if (NameLookup.VERBOSE) { AJLog.log(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " //$NON-NLS-1$ + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ AJLog.log(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " //$NON-NLS-1$ + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ } }
From source file:org.eclipse.ajdt.core.model.AJProjectModelFacade.java
License:Open Source License
/** * Open up the buffer to to convert from line number to offset * this is slow/*from www . j a va 2 s .co m*/ * We are always working in an AJCU with an aspect element * * cache the results since it is likely that we will be * calling this often for the same sloc */ private int offsetFromLine(ITypeRoot unit, ISourceLocation sloc) throws JavaModelException { if (sloc.getOffset() > 0) { return sloc.getOffset(); } if (slocCache != null && slocCache.containsKey(sloc)) { return slocCache.get(sloc).intValue(); } if (unit instanceof AJCompilationUnit) { AJCompilationUnit ajUnit = (AJCompilationUnit) unit; ajUnit.requestOriginalContentMode(); } IBuffer buf = unit.getBuffer(); if (unit instanceof AJCompilationUnit) { AJCompilationUnit ajUnit = (AJCompilationUnit) unit; ajUnit.discardOriginalContentMode(); } if (buf != null) { int requestedLine = sloc.getLine(); int currentLine = 1; int offset = 0; while (offset < buf.getLength() && currentLine < requestedLine) { if (buf.getChar(offset++) == '\n') { currentLine++; } } while (offset < buf.getLength() && Character.isWhitespace(buf.getChar(offset))) { offset++; } // cache if (slocCache == null) { slocCache = new HashMap<ISourceLocation, Integer>(); } slocCache.put(sloc, new Integer(offset)); return offset; } // no source code return 0; }
From source file:org.eclipse.andmore.internal.build.ConvertSwitchQuickFixProcessor.java
License:Open Source License
@Override public IJavaCompletionProposal[] getCorrections(IInvocationContext context, IProblemLocation[] location) throws CoreException { if (location == null || location.length == 0) { return null; }/*w w w .j a v a2 s .c o m*/ ASTNode coveringNode = context.getCoveringNode(); if (coveringNode == null) { return null; } // Look up the fully qualified name of the non-constant expression, if any, and // make sure it's R-something. if (coveringNode.getNodeType() == ASTNode.SIMPLE_NAME) { coveringNode = coveringNode.getParent(); if (coveringNode == null) { return null; } } if (coveringNode.getNodeType() != ASTNode.QUALIFIED_NAME) { return null; } QualifiedName name = (QualifiedName) coveringNode; if (!name.getFullyQualifiedName().startsWith("R.")) { //$NON-NLS-1$ return null; } IProblemLocation error = location[0]; int errorStart = error.getOffset(); int errorLength = error.getLength(); int caret = context.getSelectionOffset(); // Even though the hasCorrections() method above will return false for everything // other than non-constant expression errors, it turns out this getCorrections() // method will ALSO be called on lines where there is no such error. In particular, // if you have an invalid cast expression like this: // Button button = findViewById(R.id.textView); // then this method will be called, and the expression will pass all of the above // checks. However, we -don't- want to show a migrate code suggestion in that case! // Therefore, we'll need to check if we're *actually* on a line with the given // problem. // // Unfortunately, we don't get passed the problemId again, and there's no access // to it. So instead we'll need to look up the markers on the line, and see // if we actually have a constant expression warning. This is not pretty!! boolean foundError = false; ICompilationUnit compilationUnit = context.getCompilationUnit(); IResource file = compilationUnit.getResource(); if (file != null) { IDocumentProvider provider = new TextFileDocumentProvider(); try { provider.connect(file); IDocument document = provider.getDocument(file); if (document != null) { List<IMarker> markers = AdtUtils.findMarkersOnLine(IMarker.PROBLEM, file, document, errorStart); for (IMarker marker : markers) { String message = marker.getAttribute(IMarker.MESSAGE, ""); // There are no other attributes in the marker we can use to identify // the exact error, so we'll need to resort to the actual message // text even though that would not work if the messages had been // localized... This can also break if the error messages change. Yuck. if (message.contains("constant expressions")) { //$NON-NLS-1$ foundError = true; } } } } catch (Exception e) { AndmoreAndroidPlugin.log(e, "Can't validate error message in %1$s", file.getName()); } finally { provider.disconnect(file); } } if (!foundError) { // Not a constant-expression warning, so do nothing return null; } IBuffer buffer = compilationUnit.getBuffer(); boolean sameLine = false; // See if the caret is on the same line as the error if (caret <= errorStart) { // Search backwards to beginning of line for (int i = errorStart; i >= 0; i--) { if (i <= caret) { sameLine = true; break; } char c = buffer.getChar(i); if (c == '\n') { break; } } } else { // Search forwards to the end of the line for (int i = errorStart + errorLength, n = buffer.getLength(); i < n; i++) { if (i >= caret) { sameLine = true; break; } char c = buffer.getChar(i); if (c == '\n') { break; } } } if (sameLine) { String expression = buffer.getText(errorStart, errorLength); return new IJavaCompletionProposal[] { new MigrateProposal(expression) }; } return null; }
From source file:org.eclipse.andmore.internal.refactorings.extractstring.ExtractStringProposal.java
License:Open Source License
@Override public String getAdditionalProposalInfo() { try {// www . j a va 2 s.c o m ASTNode coveringNode = mContext.getCoveringNode(); int start = coveringNode.getStartPosition(); int length = coveringNode.getLength(); IBuffer buffer = mContext.getCompilationUnit().getBuffer(); StringBuilder sb = new StringBuilder(); String string = buffer.getText(start, length); string = ExtractStringRefactoring.unquoteAttrValue(string); String token = ExtractStringInputPage.guessId(string); // Look up the beginning and the end of the line (outside of the extracted string) // such that we can show a preview of the diff, e.g. if you have // foo.setTitle("Hello"); we want to show foo.setTitle(R.string.hello); // so we need to extract "foo.setTitle(" and ");". // Look backwards to the beginning of the line (and strip whitespace) int i = start - 1; while (i > 0) { char c = buffer.getChar(i); if (c == '\r' || (c == '\n')) { break; } i--; } String linePrefix = buffer.getText(i + 1, start - (i + 1)).trim(); // Look forwards to the end of the line (and strip whitespace) i = start + length; while (i < buffer.getLength()) { char c = buffer.getChar(i); if (c == '\r' || (c == '\n')) { break; } i++; } String lineSuffix = buffer.getText(start + length, i - (start + length)); // Should we show the replacement as just R.string.foo or // context.getString(R.string.foo) ? boolean useContext = false; ASTNode parent = coveringNode.getParent(); if (parent != null) { int type = parent.getNodeType(); if (type == ASTNode.ASSIGNMENT || type == ASTNode.VARIABLE_DECLARATION_STATEMENT || type == ASTNode.VARIABLE_DECLARATION_FRAGMENT || type == ASTNode.VARIABLE_DECLARATION_EXPRESSION) { useContext = true; } } // Display .java change: sb.append("...<br>"); //$NON-NLS-1$ sb.append(linePrefix); sb.append("<b>"); //$NON-NLS-1$ if (useContext) { sb.append("context.getString("); //$NON-NLS-1$ } sb.append("R.string."); //$NON-NLS-1$ sb.append(token); if (useContext) { sb.append(")"); //$NON-NLS-1$ } sb.append("</b>"); //$NON-NLS-1$ sb.append(lineSuffix); sb.append("<br>...<br>"); //$NON-NLS-1$ // Display strings.xml change: sb.append("<br>"); //$NON-NLS-1$ sb.append("<resources><br>"); //$NON-NLS-1$ sb.append(" <b><string name=\""); //$NON-NLS-1$ sb.append(token); sb.append("\">"); //$NON-NLS-1$ sb.append(string); sb.append("</string></b><br>"); //$NON-NLS-1$ sb.append("</resources>"); //$NON-NLS-1$ return sb.toString(); } catch (JavaModelException e) { AndmoreAndroidPlugin.log(e, null); } return "Initiates the Extract String refactoring operation"; }