diff options
15 files changed, 293 insertions, 22 deletions
| diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java b/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java index 5991026..582ac09 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java @@ -258,8 +258,9 @@ public class Client {                  if (canStream) {                      HandleProfiling.sendMPSS(this, 8*1024*1024, 0 /*flags*/);                  } else { -                    String file = "/sdcard/" + mClientData.getClientDescription().replaceAll("\\:.*", "") + -                    ".trace"; +                    String file = "/sdcard/" + +                        mClientData.getClientDescription().replaceAll("\\:.*", "") + +                        DdmConstants.DOT_TRACE;                      HandleProfiling.sendMPRS(this, file, 8*1024*1024, 0 /*flags*/);                  }              } diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/DdmConstants.java b/ddms/libs/ddmlib/src/com/android/ddmlib/DdmConstants.java index d9823f3..0b107e4 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/DdmConstants.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/DdmConstants.java @@ -29,6 +29,11 @@ public final class DdmConstants {       */      public final static int CURRENT_PLATFORM = currentPlatform(); +    /** +     * Extension for Traceview files. +     */ +    public final static String DOT_TRACE = ".trace"; +      /** hprof-conv executable (with extension for the current OS)  */      public final static String FN_HPROF_CONVERTER = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?              "hprof-conv.exe" : "hprof-conv"; //$NON-NLS-1$ //$NON-NLS-2$ diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java b/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java index 0595267..9d01fdf 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java @@ -88,7 +88,7 @@ final class HandleProfiling extends ChunkHandler {       * android.os.Debug.startMethodTracing() on the device.       *       * @param fileName is the name of the file to which profiling data -     *          will be written (on the device); it will have ".trace" +     *          will be written (on the device); it will have {@link DdmConstants#DOT_TRACE}       *          appended if necessary       * @param bufferSize is the desired buffer size in bytes (8MB is good)       * @param flags see startMethodTracing() docs; use 0 for default behavior diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java index a44bd1a..a0febeb 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java @@ -17,6 +17,7 @@  package com.android.ddmuilib.explorer;  import com.android.ddmlib.AdbCommandRejectedException; +import com.android.ddmlib.DdmConstants;  import com.android.ddmlib.FileListingService;  import com.android.ddmlib.IDevice;  import com.android.ddmlib.IShellOutputReceiver; @@ -390,7 +391,7 @@ public class DeviceExplorer extends Panel {          String path;          try {              // create a temp file for keyFile -            File f = File.createTempFile(baseName, ".trace"); +            File f = File.createTempFile(baseName, DdmConstants.DOT_TRACE);              f.delete();              f.mkdir(); diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java index 7ecf7b9..83ff0ba 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java @@ -155,8 +155,8 @@ public abstract class BaseFileHandler {       * @return the File into which the data was written or null if it failed.       * @throws IOException       */ -    protected File saveTempFile(byte[] data) throws IOException { -        File f = File.createTempFile("ddms", null); +    protected File saveTempFile(byte[] data, String extension) throws IOException { +        File f = File.createTempFile("ddms", extension);          saveFile(data, f);          return f;      } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java index f1d0135..f6e2f19 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java @@ -17,6 +17,7 @@  package com.android.ddmuilib.handler;  import com.android.ddmlib.Client; +import com.android.ddmlib.DdmConstants;  import com.android.ddmlib.IDevice;  import com.android.ddmlib.Log;  import com.android.ddmlib.SyncException; @@ -101,8 +102,8 @@ public class MethodProfilingHandler extends BaseFileHandler      public void onSuccess(byte[] data, final Client client) {          try { -            File tempFile = saveTempFile(data); -            openInTraceview(tempFile.getAbsolutePath()); +            File tempFile = saveTempFile(data, DdmConstants.DOT_TRACE); +            open(tempFile.getAbsolutePath());          } catch (IOException e) {              String errorMsg = e.getMessage();              displayErrorInUiThread( @@ -117,7 +118,7 @@ public class MethodProfilingHandler extends BaseFileHandler      private void pullAndOpen(final SyncService sync, final String remoteFilePath)              throws InvocationTargetException, InterruptedException, IOException {          // get a temp file -        File temp = File.createTempFile("android", ".trace"); //$NON-NLS-1$ //$NON-NLS-2$ +        File temp = File.createTempFile("android", DdmConstants.DOT_TRACE); //$NON-NLS-1$          final String tempPath = temp.getAbsolutePath();          // pull the file @@ -135,7 +136,7 @@ public class MethodProfilingHandler extends BaseFileHandler                  String.format("Pulling %1$s from the device", remoteFilePath), mParentShell);              // open the temp file in traceview -            openInTraceview(tempPath); +            open(tempPath);          } catch (SyncException e) {              if (e.wasCanceled() == false) {                  displayErrorFromUiThread("Unable to download trace file:\n\n%1$s", e.getMessage()); @@ -145,7 +146,7 @@ public class MethodProfilingHandler extends BaseFileHandler          }      } -    private void openInTraceview(String tempPath) { +    protected void open(String tempPath) {          // now that we have the file, we need to launch traceview          String[] command = new String[2];          command[0] = DdmUiPreferences.getTraceview(); diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml index 02d570e..9bc5a0c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml @@ -4,6 +4,7 @@     <extension-point id="toolsLocator" name="Tools Locator" schema="schema/toolsLocator.exsd"/>     <extension-point id="debuggerConnector" name="Debugger Connector" schema="schema/debuggerConnector.exsd"/>     <extension-point id="sourceRevealer" name="Source Revealer" schema="schema/sourceRevealer.exsd"/> +   <extension-point id="traceviewLauncher" name="TraceView Launcher" schema="schema/traceviewLauncher.exsd"/>     <extension           point="org.eclipse.ui.views"> diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/schema/traceviewLauncher.exsd b/eclipse/plugins/com.android.ide.eclipse.ddms/schema/traceviewLauncher.exsd new file mode 100644 index 0000000..daca83a --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/schema/traceviewLauncher.exsd @@ -0,0 +1,100 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- Schema file written by PDE --> +<schema targetNamespace="com.android.ide.eclipse.ddms" xmlns="http://www.w3.org/2001/XMLSchema"> +<annotation> +      <appInfo> +         <meta.schema plugin="com.android.ide.eclipse.ddms" id="traceviewLauncher" name="Traceview Launcher"/> +      </appInfo> +      <documentation> +         Extension Point to launch Traceview. +      </documentation> +   </annotation> + +   <element name="launcher"> +      <complexType> +         <attribute name="class" type="string" use="required"> +            <annotation> +               <documentation> +               </documentation> +               <appInfo> +                  <meta.attribute kind="java" basedOn=":com.android.ide.eclipse.ddms.ITraceviewLauncher"/> +               </appInfo> +            </annotation> +         </attribute> +      </complexType> +   </element> + +   <element name="extension"> +      <annotation> +         <appInfo> +            <meta.element /> +         </appInfo> +      </annotation> +      <complexType> +         <sequence> +            <element ref="launcher"/> +         </sequence> +         <attribute name="point" type="string" use="required"> +            <annotation> +               <documentation> +               </documentation> +            </annotation> +         </attribute> +         <attribute name="id" type="string"> +            <annotation> +               <documentation> +               </documentation> +            </annotation> +         </attribute> +         <attribute name="name" type="string"> +            <annotation> +               <documentation> +               </documentation> +               <appInfo> +                  <meta.attribute translatable="true"/> +               </appInfo> +            </annotation> +         </attribute> +      </complexType> +   </element> + +   <annotation> +      <appInfo> +         <meta.section type="since"/> +      </appInfo> +      <documentation> +         10.0.0 +      </documentation> +   </annotation> + +   <annotation> +      <appInfo> +         <meta.section type="examples"/> +      </appInfo> +      <documentation> +         <extension point="com.android.ide.eclipse.ddms.traceviewLauncher"> +    <launcher class="com.android.ide.eclipse.adt.Launcher"/> +</extension> +      </documentation> +   </annotation> + +   <annotation> +      <appInfo> +         <meta.section type="apiinfo"/> +      </appInfo> +      <documentation> +         The class must implement com.android.ide.ddms.ITraceviewLauncher. +      </documentation> +   </annotation> + + +   <annotation> +      <appInfo> +         <meta.section type="copyright"/> +      </appInfo> +      <documentation> +         Copyright (C) 2011 The Android Open Source Project +      </documentation> +   </annotation> + +</schema> diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java index 182f91d..298953a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java @@ -82,6 +82,7 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL       */      private IDebuggerConnector[] mDebuggerConnectors;      private ISourceRevealer[] mSourceRevealers; +    private ITraceviewLauncher[] mTraceviewLaunchers;      /** Console for DDMS log message */ @@ -253,6 +254,7 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL          // get the other configElements and instantiante them in a Job.          new Job("DDMS post-create init") { +              @Override              protected IStatus run(IProgressMonitor monitor) {                  try { @@ -295,6 +297,10 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL                      elements = findConfigElements("com.android.ide.eclipse.ddms.sourceRevealer"); //$NON-NLS-1$                      mSourceRevealers = instantiateSourceRevealers(elements); +                    // get the available Traceview Launchers. +                    elements = findConfigElements("com.android.ide.eclipse.ddms.traceviewLauncher"); //$NON-NLS-1$ +                    mTraceviewLaunchers = instantiateTraceviewLauncher(elements); +                      return Status.OK_STATUS;                  } catch (CoreException e) {                      return e.getStatus(); @@ -329,7 +335,7 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL              // only use the first one, ignore the others.              IConfigurationElement configElement = configElements[0]; -            // instantiate the clas +            // instantiate the class              Object obj = configElement.createExecutableExtension("class"); //$NON-NLS-1$              if (obj instanceof IToolsLocator) {                  list.add((IToolsLocator) obj); @@ -352,7 +358,7 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL              // only use the first one, ignore the others.              IConfigurationElement configElement = configElements[0]; -            // instantiate the clas +            // instantiate the class              Object obj = configElement.createExecutableExtension("class"); //$NON-NLS-1$              if (obj instanceof IDebuggerConnector) {                  list.add((IDebuggerConnector) obj); @@ -375,7 +381,7 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL              // only use the first one, ignore the others.              IConfigurationElement configElement = configElements[0]; -            // instantiate the clas +            // instantiate the class              Object obj = configElement.createExecutableExtension("class"); //$NON-NLS-1$              if (obj instanceof ISourceRevealer) {                  list.add((ISourceRevealer) obj); @@ -385,6 +391,30 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL          return list.toArray(new ISourceRevealer[list.size()]);      } +    /** +     * Finds if any other plug-in is extending the exposed Extension Point called traceviewLauncher. +     * +     * @return an array of all locators found, or an empty array if none were found. +     */ +    private ITraceviewLauncher[] instantiateTraceviewLauncher( +            IConfigurationElement[] configElements) +            throws CoreException { +        ArrayList<ITraceviewLauncher> list = new ArrayList<ITraceviewLauncher>(); + +        if (configElements.length > 0) { +            // only use the first one, ignore the others. +            IConfigurationElement configElement = configElements[0]; + +            // instantiate the class +            Object obj = configElement.createExecutableExtension("class"); //$NON-NLS-1$ +            if (obj instanceof ITraceviewLauncher) { +                list.add((ITraceviewLauncher) obj); +            } +        } + +        return list.toArray(new ITraceviewLauncher[list.size()]); +    } +      public static Display getDisplay() {          IWorkbench bench = sPlugin.getWorkbench();          if (bench != null) { @@ -733,4 +763,20 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL              }          }      } + +    public boolean launchTraceview(String osPath) { +        if (mTraceviewLaunchers != null) { +            for (ITraceviewLauncher launcher : mTraceviewLaunchers) { +                try { +                    if (launcher.openFile(osPath)) { +                        return true; +                    } +                } catch (Throwable t) { +                    // ignore, we'll just not use this implementation. +                } +            } +        } + +        return false; +    }  } diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/ITraceviewLauncher.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/ITraceviewLauncher.java new file mode 100644 index 0000000..7542b88 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/ITraceviewLauncher.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms; + +/** + * Classes which implement this interface provides a way to open a traceview file. + */ +public interface ITraceviewLauncher { + +    boolean openFile(String osPath); +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java index 0fa33d2..4ecee92 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java @@ -201,7 +201,9 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien                      if (ACTION_OPEN.equals(value)) {                          try { -                            File tempFile = saveTempFile(data); +                            // no need to give an extension since we're going to convert the +                            // file anyway after. +                            File tempFile = saveTempFile(data, null /*extension*/);                              open(tempFile.getAbsolutePath());                          } catch (Exception e) {                              String errorMsg = e.getMessage(); @@ -252,14 +254,11 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien                      }                  } -                IDE.openEditorOnFileStore( -                        getSite().getWorkbenchWindow().getActivePage(), -                        fileStore); +                IDE.openEditorOnFileStore(page, fileStore);              }          }      } -      public DeviceView() {          // the view is declared with allowMultiple="false" so we          // can safely do this. @@ -455,7 +454,14 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien          ClientData.setHprofDumpHandler(new HProfHandler(mParentShell));          AndroidDebugBridge.addClientChangeListener(this); -        ClientData.setMethodProfilingHandler(new MethodProfilingHandler(mParentShell)); +        ClientData.setMethodProfilingHandler(new MethodProfilingHandler(mParentShell) { +            @Override +            protected void open(String tempPath) { +                if (DdmsPlugin.getDefault().launchTraceview(tempPath) == false) { +                    super.open(tempPath); +                } +            } +        });      }      @Override diff --git a/eclipse/plugins/com.android.ide.eclipse.traceview/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.traceview/META-INF/MANIFEST.MF index 0459a07..623076a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.traceview/META-INF/MANIFEST.MF +++ b/eclipse/plugins/com.android.ide.eclipse.traceview/META-INF/MANIFEST.MF @@ -6,7 +6,10 @@ Bundle-Version: 10.0.0.qualifier  Bundle-Activator: com.android.ide.eclipse.traceview.TraceviewPlugin  Require-Bundle: org.eclipse.ui,   org.eclipse.core.runtime, - org.eclipse.ui.ide + org.eclipse.ui.ide, + com.android.ide.eclipse.ddms;bundle-version="10.0.0", + org.eclipse.core.filesystem, + org.eclipse.core.resources  Bundle-ActivationPolicy: lazy  Bundle-ClassPath: .,   libs/traceview.jar diff --git a/eclipse/plugins/com.android.ide.eclipse.traceview/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.traceview/plugin.xml index a6ab5d4..042a630 100644 --- a/eclipse/plugins/com.android.ide.eclipse.traceview/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.traceview/plugin.xml @@ -6,11 +6,17 @@        <editor              class="com.android.ide.eclipse.traceview.editors.TraceviewEditor"              default="true" -            extensions="atv" +            extensions="trace"              icon="icons/android.png"              id="com.android.ide.eclipse.traceview.editors.TraceviewEditor"              name="Traceview">        </editor>     </extension> +   <extension +         point="com.android.ide.eclipse.ddms.traceviewLauncher"> +      <launcher +            class="com.android.ide.eclipse.traceview.TraceviewLauncher"> +      </launcher> +   </extension>  </plugin> diff --git a/eclipse/plugins/com.android.ide.eclipse.traceview/src/com/android/ide/eclipse/traceview/TraceviewLauncher.java b/eclipse/plugins/com.android.ide.eclipse.traceview/src/com/android/ide/eclipse/traceview/TraceviewLauncher.java new file mode 100644 index 0000000..502084f --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.traceview/src/com/android/ide/eclipse/traceview/TraceviewLauncher.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.traceview; + +import com.android.ide.eclipse.ddms.ITraceviewLauncher; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.Path; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.WorkbenchException; +import org.eclipse.ui.ide.IDE; + +public class TraceviewLauncher implements ITraceviewLauncher { + +    public boolean openFile(String osPath) { +        final IFileStore fileStore =  EFS.getLocalFileSystem().getStore(new Path(osPath)); +        if (!fileStore.fetchInfo().isDirectory() && fileStore.fetchInfo().exists()) { +            // before we open the file in an editor window, we make sure the current +            // workbench page has an editor area (typically the ddms perspective doesn't). +            final IWorkbench workbench = PlatformUI.getWorkbench(); +            Display display = workbench.getDisplay(); +            final boolean[] result = new boolean[] { false }; +            display.syncExec(new Runnable() { +                public void run() { +                    IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); +                    IWorkbenchPage page = window.getActivePage(); +                    if (page.isEditorAreaVisible() == false) { +                        IAdaptable input; +                        if (page != null) +                            input= page.getInput(); +                        else +                            input= ResourcesPlugin.getWorkspace().getRoot(); +                        try { +                            workbench.showPerspective("org.eclipse.debug.ui.DebugPerspective", +                                    window, input); +                        } catch (WorkbenchException e) { +                        } +                    } + +                    try { +                        result[0] = IDE.openEditorOnFileStore(page, fileStore) != null; +                    } catch (PartInitException e) { +                        // return false below +                    } +                } +            }); + +            return result[0]; +        } + +        return false; +    } +} diff --git a/eclipse/sites/internal/site.xml b/eclipse/sites/internal/site.xml index afdccb2..40abd3b 100644 --- a/eclipse/sites/internal/site.xml +++ b/eclipse/sites/internal/site.xml @@ -21,6 +21,7 @@        <category name="platform"/>     </feature>     <feature url="features/com.android.ide.eclipse.traceview_10.0.0.qualifier.jar" id="com.android.ide.eclipse.traceview" version="10.0.0.qualifier"> +      <category name="developer"/>        <category name="platform"/>     </feature>     <category-def name="developer" label="Application Developer Tools"> | 
