+ compilerConfig.getNonStandardOptions() + "\n-> javaoptions:" + formatMap(compilerConfig.getJavaOptionsMap()); | + compilerConfig.getNonStandardOptions() + "\n-> javaoptions:" + formatMap(compilerConfig.getJavaOptionsMap()); | ||||
} | } | ||||
private String formatCollection(Collection<?> options) { | |||||
private String formatCollection(Collection<File> options) { | |||||
if (options == null) { | if (options == null) { | ||||
return "<default>"; | return "<default>"; | ||||
} | } | ||||
} | } | ||||
StringBuilder formattedOptions = new StringBuilder(); | StringBuilder formattedOptions = new StringBuilder(); | ||||
for (Object option : options) { | |||||
for (File option : options) { | |||||
String o = option.toString(); | String o = option.toString(); | ||||
if (formattedOptions.length() > 0) { | if (formattedOptions.length() > 0) { | ||||
formattedOptions.append(", "); | formattedOptions.append(", "); |
showWarningMessage("No main class specified"); | showWarningMessage("No main class specified"); | ||||
} else { | } else { | ||||
StringBuilder sb = new StringBuilder(); | StringBuilder sb = new StringBuilder(); | ||||
List outputDirs = compilerConfig.getOutputLocationManager().getAllOutputLocations(); | |||||
for (Object outputDir : outputDirs) { | |||||
File dir = (File) outputDir; | |||||
List<File> outputDirs = compilerConfig.getOutputLocationManager().getAllOutputLocations(); | |||||
for (File dir : outputDirs) { | |||||
sb.append(dir.getAbsolutePath() + File.pathSeparator); | sb.append(dir.getAbsolutePath() + File.pathSeparator); | ||||
} | } | ||||
classpath = LangUtil.makeClasspath(null, compilerConfig.getClasspath(), sb.toString(), compilerConfig.getOutJar()); | classpath = LangUtil.makeClasspath(null, compilerConfig.getClasspath(), sb.toString(), compilerConfig.getOutJar()); |
if (properties.getFilteredMemberKinds().contains(pNode.getKind())) { | if (properties.getFilteredMemberKinds().contains(pNode.getKind())) { | ||||
return false; | return false; | ||||
} | } | ||||
for (Object element : pNode.getModifiers()) { | |||||
for (IProgramElement.Modifiers element : pNode.getModifiers()) { | |||||
if (properties.getFilteredMemberModifiers().contains(element)) { | if (properties.getFilteredMemberModifiers().contains(element)) { | ||||
return false; | return false; | ||||
} | } |
} | } | ||||
public void saveOptions() throws IOException { | public void saveOptions() throws IOException { | ||||
Set s = warningComboBoxes.entrySet(); | |||||
for (Object o : s) { | |||||
Entry entry = (Entry) o; | |||||
String javaOption = (String) entry.getKey(); | |||||
JComboBox combo = (JComboBox) entry.getValue(); | |||||
Set<Entry<String, JComboBox>> s = warningComboBoxes.entrySet(); | |||||
for (Entry<String, JComboBox> entry : s) { | |||||
String javaOption = entry.getKey(); | |||||
JComboBox combo = entry.getValue(); | |||||
String value = (String) combo.getSelectedItem(); | String value = (String) combo.getSelectedItem(); | ||||
javaBuildOptions.setOption(javaOption, value); | javaBuildOptions.setOption(javaOption, value); | ||||
} | } |
Set<String> deletedNodes = new HashSet<>(); | Set<String> deletedNodes = new HashSet<>(); | ||||
for (File fileForCompilation : files) { | for (File fileForCompilation : files) { | ||||
String correctedPath = getCanonicalFilePath(fileForCompilation); | String correctedPath = getCanonicalFilePath(fileForCompilation); | ||||
IProgramElement progElem = (IProgramElement) hierarchy.findInFileMap(correctedPath); | |||||
IProgramElement progElem = hierarchy.findInFileMap(correctedPath); | |||||
if (progElem != null) { | if (progElem != null) { | ||||
// Found it, let's remove it | // Found it, let's remove it | ||||
if (dumpDeltaProcessing) { | if (dumpDeltaProcessing) { |
setFileMap((Map<String, IProgramElement>) fileMap); | setFileMap((Map<String, IProgramElement>) fileMap); | ||||
} | } | ||||
Object findInFileMap(Object key); | |||||
IProgramElement findInFileMap(String key); | |||||
Set<Map.Entry<String, IProgramElement>> getFileMapEntrySet(); | Set<Map.Entry<String, IProgramElement>> getFileMapEntrySet(); | ||||
this.fileMap = fileMap; | this.fileMap = fileMap; | ||||
} | } | ||||
public Object findInFileMap(Object key) { | |||||
public IProgramElement findInFileMap(String key) { | |||||
return fileMap.get(key); | return fileMap.get(key); | ||||
} | } | ||||
} else { | } else { | ||||
String correctedPath = asm.getCanonicalFilePath(new File(sourceFile)); | String correctedPath = asm.getCanonicalFilePath(new File(sourceFile)); | ||||
// StructureNode node = (StructureNode)getFileMap().get(correctedPath);//findFileNode(filePath, model); | // StructureNode node = (StructureNode)getFileMap().get(correctedPath);//findFileNode(filePath, model); | ||||
IProgramElement node = (IProgramElement) findInFileMap(correctedPath);// findFileNode(filePath, model); | |||||
IProgramElement node = findInFileMap(correctedPath);// findFileNode(filePath, model); | |||||
if (node != null) { | if (node != null) { | ||||
return node; | return node; | ||||
} else { | } else { |
buf.append(text.substring(lastIndex, startIndex)); | buf.append(text.substring(lastIndex, startIndex)); | ||||
String key = text.substring(startIndex + 2, endIndex); | String key = text.substring(startIndex + 2, endIndex); | ||||
lastIndex = endIndex + 1; | lastIndex = endIndex + 1; | ||||
Object replaceText = (map == null ? null : map.get(key)); | |||||
String replaceText = (map == null ? null : map.get(key)); | |||||
//System.out.println("key: " + key + " -> " + replaceText); | //System.out.println("key: " + key + " -> " + replaceText); | ||||
if (replaceText == null) { | if (replaceText == null) { | ||||
replaceText = "NOT_FOUND"; | replaceText = "NOT_FOUND"; |
private final File tempDir; | private final File tempDir; | ||||
private final List tempFiles; | |||||
private final List<File> tempFiles; | |||||
private final boolean useEclipseCompiles; | private final boolean useEclipseCompiles; | ||||
Util.iaxIfNull(handler, "handler"); | Util.iaxIfNull(handler, "handler"); | ||||
this.useEclipseCompiles = useEclipseCompiles; | this.useEclipseCompiles = useEclipseCompiles; | ||||
this.handler = handler; | this.handler = handler; | ||||
this.tempFiles = new ArrayList(); | |||||
this.tempFiles = new ArrayList<>(); | |||||
if ((null == tempDir) || !tempDir.canWrite() || !tempDir.isDirectory()) { | if ((null == tempDir) || !tempDir.canWrite() || !tempDir.isDirectory()) { | ||||
this.tempDir = Util.makeTempDir("Builder"); | this.tempDir = Util.makeTempDir("Builder"); | ||||
} else { | } else { | ||||
*/ | */ | ||||
public boolean cleanup() { | public boolean cleanup() { | ||||
boolean noErr = true; | boolean noErr = true; | ||||
for (Object tempFile : tempFiles) { | |||||
File file = (File) tempFile; | |||||
for (File file : tempFiles) { | |||||
if (!Util.deleteContents(file) || !file.delete()) { | if (!Util.deleteContents(file) || !file.delete()) { | ||||
if (noErr) { | if (noErr) { | ||||
noErr = false; | noErr = false; |
public static final String SAMPLE_BASE_DIR_NAME = "sandbox"; | public static final String SAMPLE_BASE_DIR_NAME = "sandbox"; | ||||
public static void simpleRender(Samples result, StringBuffer sink) { | public static void simpleRender(Samples result, StringBuffer sink) { | ||||
List sortedSamples = result.getSortedSamples(); | |||||
List<Sample> sortedSamples = result.getSortedSamples(); | |||||
int i = 0; | int i = 0; | ||||
for (Object sortedSample : sortedSamples) { | |||||
Sample sample = (Sample) sortedSample; | |||||
for (Sample sample : sortedSamples) { | |||||
sink.append(i++ + ": " + sample); | sink.append(i++ + ": " + sample); | ||||
} | } | ||||
} | } |
*******************************************************************************/ | *******************************************************************************/ | ||||
package org.aspectj.weaver.loadtime; | package org.aspectj.weaver.loadtime; | ||||
import java.lang.ref.Reference; | |||||
import java.lang.ref.ReferenceQueue; | import java.lang.ref.ReferenceQueue; | ||||
import java.lang.ref.WeakReference; | import java.lang.ref.WeakReference; | ||||
import java.security.ProtectionDomain; | import java.security.ProtectionDomain; | ||||
* should tidy up the adaptor map and remove the adaptor (weaver) from the map we are maintaining from adaptorkey > adaptor | * should tidy up the adaptor map and remove the adaptor (weaver) from the map we are maintaining from adaptorkey > adaptor | ||||
* (weaver) | * (weaver) | ||||
*/ | */ | ||||
private static ReferenceQueue adaptorQueue = new ReferenceQueue(); | |||||
private static ReferenceQueue<ClassLoader> adaptorQueue = new ReferenceQueue<>(); | |||||
private static Trace trace = TraceFactory.getTraceFactory().getTrace(Aj.class); | private static Trace trace = TraceFactory.getTraceFactory().getTrace(Aj.class); | ||||
System.err.println("Weaver adaptors before queue processing:"); | System.err.println("Weaver adaptors before queue processing:"); | ||||
Map<AdaptorKey,ExplicitlyInitializedClassLoaderWeavingAdaptor> m = WeaverContainer.weavingAdaptors; | Map<AdaptorKey,ExplicitlyInitializedClassLoaderWeavingAdaptor> m = WeaverContainer.weavingAdaptors; | ||||
Set<AdaptorKey> keys = m.keySet(); | Set<AdaptorKey> keys = m.keySet(); | ||||
for (Object object : keys) { | |||||
for (AdaptorKey object : keys) { | |||||
System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object)); | System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object)); | ||||
} | } | ||||
} | } | ||||
Object o = adaptorQueue.poll(); | |||||
Reference<?> o = adaptorQueue.poll(); | |||||
while (o != null) { | while (o != null) { | ||||
if (displayProgress) | if (displayProgress) | ||||
System.err.println("Processing referencequeue entry " + o); | System.err.println("Processing referencequeue entry " + o); | ||||
System.err.println("Weaver adaptors after queue processing:"); | System.err.println("Weaver adaptors after queue processing:"); | ||||
Map<AdaptorKey,ExplicitlyInitializedClassLoaderWeavingAdaptor> m = WeaverContainer.weavingAdaptors; | Map<AdaptorKey,ExplicitlyInitializedClassLoaderWeavingAdaptor> m = WeaverContainer.weavingAdaptors; | ||||
Set<AdaptorKey> keys = m.keySet(); | Set<AdaptorKey> keys = m.keySet(); | ||||
for (Object object : keys) { | |||||
for (AdaptorKey object : keys) { | |||||
System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object)); | System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object)); | ||||
} | } | ||||
} | } | ||||
*/ | */ | ||||
public static void checkQ() { | public static void checkQ() { | ||||
synchronized (adaptorQueue) { | synchronized (adaptorQueue) { | ||||
Object o = adaptorQueue.poll(); | |||||
Reference<?> o = adaptorQueue.poll(); | |||||
while (o != null) { | while (o != null) { | ||||
AdaptorKey wo = (AdaptorKey) o; | AdaptorKey wo = (AdaptorKey) o; | ||||
// boolean removed = | // boolean removed = |
import org.aspectj.weaver.bcel.BcelObjectType; | import org.aspectj.weaver.bcel.BcelObjectType; | ||||
import org.aspectj.weaver.bcel.FakeAnnotation; | import org.aspectj.weaver.bcel.FakeAnnotation; | ||||
import org.aspectj.weaver.bcel.LazyClassGen; | import org.aspectj.weaver.bcel.LazyClassGen; | ||||
import org.aspectj.weaver.patterns.Declare; | |||||
import org.aspectj.weaver.patterns.DeclareAnnotation; | import org.aspectj.weaver.patterns.DeclareAnnotation; | ||||
import org.aspectj.weaver.patterns.DeclareParents; | import org.aspectj.weaver.patterns.DeclareParents; | ||||
} | } | ||||
} | } | ||||
List<Object> forRemoval = new ArrayList<>(); | |||||
List<Declare> forRemoval = new ArrayList<>(); | |||||
// now lets loop over and over until we have done all we can | // now lets loop over and over until we have done all we can | ||||
while ((anyNewAnnotations || anyNewParents) && (!decpToRepeat.isEmpty() || !decaToRepeat.isEmpty())) { | while ((anyNewAnnotations || anyNewParents) && (!decpToRepeat.isEmpty() || !decaToRepeat.isEmpty())) { | ||||
anyNewParents = anyNewAnnotations = false; | anyNewParents = anyNewAnnotations = false; |
AspectDeclaration ad = (AspectDeclaration) typeDecl.enclosingType; | AspectDeclaration ad = (AspectDeclaration) typeDecl.enclosingType; | ||||
if (ad.concreteName != null) { | if (ad.concreteName != null) { | ||||
List<Declare> declares = ad.concreteName.declares; | List<Declare> declares = ad.concreteName.declares; | ||||
for (Object dec : declares) { | |||||
for (Declare dec : declares) { | |||||
if (dec instanceof DeclareParents) { | if (dec instanceof DeclareParents) { | ||||
DeclareParents decp = (DeclareParents) dec; | DeclareParents decp = (DeclareParents) dec; | ||||
TypePattern[] newparents = decp.getParents().getTypePatterns(); | TypePattern[] newparents = decp.getParents().getTypePatterns(); |
setMakeReflectable(global.isMakeReflectable()); | setMakeReflectable(global.isMakeReflectable()); | ||||
} | } | ||||
@SuppressWarnings({ "rawtypes", "unchecked" }) | |||||
void join(Collection local, Collection global) { | |||||
for (Object next : global) { | |||||
<T> void join(Collection<T> local, Collection<T> global) { | |||||
for (T next : global) { | |||||
if (!local.contains(next)) { | if (!local.contains(next)) { | ||||
local.add(next); | local.add(next); | ||||
} | } |
} | } | ||||
} | } | ||||
private ByteArrayOutputStream getOutxmlContents(List aspectNames) { | |||||
private ByteArrayOutputStream getOutxmlContents(List<String> aspectNames) { | |||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||||
PrintStream ps = new PrintStream(baos); | PrintStream ps = new PrintStream(baos); | ||||
ps.println("<aspectj>"); | ps.println("<aspectj>"); | ||||
ps.println("<aspects>"); | ps.println("<aspects>"); | ||||
if (aspectNames != null) { | if (aspectNames != null) { | ||||
for (Object aspectName : aspectNames) { | |||||
String name = (String) aspectName; | |||||
for (String name : aspectNames) { | |||||
ps.println("<aspect name=\"" + name + "\"/>"); | ps.println("<aspect name=\"" + name + "\"/>"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
outputDirsToAspects.put(outputDir, aspectNames); | outputDirsToAspects.put(outputDir, aspectNames); | ||||
} else { | } else { | ||||
List outputDirs = buildConfig.getCompilationResultDestinationManager().getAllOutputLocations(); | |||||
for (Object dir : outputDirs) { | |||||
File outputDir = (File) dir; | |||||
List<File> outputDirs = buildConfig.getCompilationResultDestinationManager().getAllOutputLocations(); | |||||
for (File outputDir : outputDirs) { | |||||
outputDirsToAspects.put(outputDir, new ArrayList<>()); | outputDirsToAspects.put(outputDir, new ArrayList<>()); | ||||
} | } | ||||
if (aspectNamesToFileNames != null) { | if (aspectNamesToFileNames != null) { |
@Override | @Override | ||||
public void set(Map<String,String> optionsMap) { | public void set(Map<String,String> optionsMap) { | ||||
super.set(optionsMap); | super.set(optionsMap); | ||||
Object optionValue; | |||||
String optionValue; | |||||
if ((optionValue = optionsMap.get(OPTION_ReportUnusedPrivateMember)) != null) { | if ((optionValue = optionsMap.get(OPTION_ReportUnusedPrivateMember)) != null) { | ||||
updateSeverity(UnusedPrivateMember, optionValue); | updateSeverity(UnusedPrivateMember, optionValue); | ||||
} | } |
* @param outputLocs the output locations that should be ignored if they occur on the paths being compared | * @param outputLocs the output locations that should be ignored if they occur on the paths being compared | ||||
* @return true if a change is detected that requires a full build | * @return true if a change is detected that requires a full build | ||||
*/ | */ | ||||
private boolean changedAndNeedsFullBuild(List oldPath, List newPath, boolean checkClassFiles, List<File> outputLocs, | |||||
private boolean changedAndNeedsFullBuild(List<File> oldPath, List<File> newPath, boolean checkClassFiles, List<File> outputLocs, | |||||
Set<String> alreadyAnalysedPaths, int pathid) { | Set<String> alreadyAnalysedPaths, int pathid) { | ||||
if (oldPath.size() != newPath.size()) { | if (oldPath.size() != newPath.size()) { | ||||
return true; | return true; | ||||
if (!oldPath.get(i).equals(newPath.get(i))) { | if (!oldPath.get(i).equals(newPath.get(i))) { | ||||
return true; | return true; | ||||
} | } | ||||
Object o = oldPath.get(i); // String on classpath, File on other paths | |||||
File f = null; | |||||
if (o instanceof String) { | |||||
f = new File((String) o); | |||||
} else { | |||||
f = (File) o; | |||||
} | |||||
File f = oldPath.get(i); | |||||
if (f.exists() && !f.isDirectory() && (f.lastModified() >= lastSuccessfulBuildTime)) { | if (f.exists() && !f.isDirectory() && (f.lastModified() >= lastSuccessfulBuildTime)) { | ||||
return true; | return true; | ||||
} | } |
try { | try { | ||||
// Set fileSet = StructureModelManager.INSTANCE.getStructureModel().getFileMap().entrySet(); | // Set fileSet = StructureModelManager.INSTANCE.getStructureModel().getFileMap().entrySet(); | ||||
Set<Map.Entry<String, IProgramElement>> fileSet = model.getHierarchy().getFileMapEntrySet(); | Set<Map.Entry<String, IProgramElement>> fileSet = model.getHierarchy().getFileMapEntrySet(); | ||||
for (Object o : fileSet) { | |||||
IProgramElement peNode = (IProgramElement) ((Map.Entry) o).getValue(); | |||||
for (Map.Entry<String, IProgramElement> o : fileSet) { | |||||
IProgramElement peNode = o.getValue(); | |||||
dumpStructureToFile(peNode); | dumpStructureToFile(peNode); | ||||
} | } | ||||
} catch (IOException ioe) { | } catch (IOException ioe) { |
* @param ext the list of modifier and annotation nodes | * @param ext the list of modifier and annotation nodes | ||||
* (element type: <code>IExtendedModifiers</code>) | * (element type: <code>IExtendedModifiers</code>) | ||||
*/ | */ | ||||
void printModifiers(List ext) { | |||||
for (Object o : ext) { | |||||
ASTNode p = (ASTNode) o; | |||||
void printModifiers(List<ASTNode> ext) { | |||||
for (ASTNode p : ext) { | |||||
p.accept(this); | p.accept(this); | ||||
this.buffer.append(" ");//$NON-NLS-1$ | this.buffer.append(" ");//$NON-NLS-1$ | ||||
} | } |
// if we dont care about shadow mungers then ignore those | // if we dont care about shadow mungers then ignore those | ||||
// typeMungers which are created to help with the implementation | // typeMungers which are created to help with the implementation | ||||
// of shadowMungers | // of shadowMungers | ||||
Set<Object> theseTypeMungers = new HashSet<>(); | |||||
Set<Object> otherTypeMungers = new HashSet<>(); | |||||
Set<ConcreteTypeMunger> theseTypeMungers = new HashSet<>(); | |||||
Set<ConcreteTypeMunger> otherTypeMungers = new HashSet<>(); | |||||
if (!careAboutShadowMungers) { | if (!careAboutShadowMungers) { | ||||
for (ConcreteTypeMunger typeMunger : typeMungers) { | for (ConcreteTypeMunger typeMunger : typeMungers) { | ||||
if (!typeMunger.existsToSupportShadowMunging()) { | if (!typeMunger.existsToSupportShadowMunging()) { | ||||
} else { | } else { | ||||
boolean shouldOverwriteThis = false; | boolean shouldOverwriteThis = false; | ||||
boolean foundInequality = false; | boolean foundInequality = false; | ||||
for (Iterator<Object> iter = theseTypeMungers.iterator(); iter.hasNext() && !foundInequality;) { | |||||
Object thisOne = iter.next(); | |||||
for (Iterator<ConcreteTypeMunger> iter = theseTypeMungers.iterator(); iter.hasNext() && !foundInequality;) { | |||||
ConcreteTypeMunger thisOne = iter.next(); | |||||
boolean foundInOtherSet = false; | boolean foundInOtherSet = false; | ||||
for (Object otherOne : otherTypeMungers) { | |||||
for (ConcreteTypeMunger otherOne : otherTypeMungers) { | |||||
if (thisOne instanceof ConcreteTypeMunger) { | if (thisOne instanceof ConcreteTypeMunger) { | ||||
if (((ConcreteTypeMunger) thisOne).shouldOverwrite()) { | |||||
if (thisOne.shouldOverwrite()) { | |||||
shouldOverwriteThis = true; | shouldOverwriteThis = true; | ||||
} | } | ||||
} | } | ||||
if (thisOne instanceof ConcreteTypeMunger && otherOne instanceof ConcreteTypeMunger) { | if (thisOne instanceof ConcreteTypeMunger && otherOne instanceof ConcreteTypeMunger) { | ||||
if (((ConcreteTypeMunger) thisOne).equivalentTo(otherOne)) { | |||||
if (thisOne.equivalentTo(otherOne)) { | |||||
foundInOtherSet = true; | foundInOtherSet = true; | ||||
} else if (thisOne.equals(otherOne)) { | } else if (thisOne.equals(otherOne)) { | ||||
foundInOtherSet = true; | foundInOtherSet = true; |
// Compare every pair of advice mungers | // Compare every pair of advice mungers | ||||
for (int i = max - 1; i >= 0; i--) { | for (int i = max - 1; i >= 0; i--) { | ||||
for (int j = 0; j < i; j++) { | for (int j = 0; j < i; j++) { | ||||
Object a = mungers.get(i); | |||||
Object b = mungers.get(j); | |||||
ShadowMunger a = mungers.get(i); | |||||
ShadowMunger b = mungers.get(j); | |||||
// Make sure they are the right type | // Make sure they are the right type | ||||
if (a instanceof Advice && b instanceof Advice) { | if (a instanceof Advice && b instanceof Advice) { |
package org.aspectj.tools.ant.taskdefs; | package org.aspectj.tools.ant.taskdefs; | ||||
import org.apache.tools.ant.Task; | |||||
import org.apache.tools.ant.taskdefs.Javac; | import org.apache.tools.ant.taskdefs.Javac; | ||||
import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter; | import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter; | ||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
if (null == javac) { | if (null == javac) { | ||||
throw new IllegalArgumentException("null javac"); | throw new IllegalArgumentException("null javac"); | ||||
} | } | ||||
Object task = javac.getProject().createTask("ajc"); | |||||
Task task = javac.getProject().createTask("ajc"); | |||||
String err = null; | String err = null; | ||||
if (null == task) { | if (null == task) { | ||||
err = "ajc not defined - put ajc taskdef library on classpath"; | err = "ajc not defined - put ajc taskdef library on classpath"; |
// package-private for testing | // package-private for testing | ||||
String[] makeCommand() { | String[] makeCommand() { | ||||
if (0 < ignored.size()) { | if (0 < ignored.size()) { | ||||
for (Object o : ignored) { | |||||
for (String o : ignored) { | |||||
logVerbose("ignored: " + o); | logVerbose("ignored: " + o); | ||||
} | } | ||||
} | } |