# HG changeset patch # User Eugene Ostroukhov # Date 1266960211 28800 # Node ID 30ef4c917204d406fef077434e00627b89a40c1f # Parent 5d205e48f9d3aa15f2762665f4b78561c64a1392 Fixed Bug 1955 - WRT Debugger "Waiting for Debugger Connection" takes an exceptionally long time diff -r 5d205e48f9d3 -r 30ef4c917204 org.chromium.sdk/.settings/org.eclipse.jdt.core.prefs --- a/org.chromium.sdk/.settings/org.eclipse.jdt.core.prefs Mon Feb 22 15:46:49 2010 -0800 +++ b/org.chromium.sdk/.settings/org.eclipse.jdt.core.prefs Tue Feb 23 13:23:31 2010 -0800 @@ -1,4 +1,4 @@ -#Mon Feb 22 15:37:52 PST 2010 +#Mon Feb 22 15:54:26 PST 2010 eclipse.preferences.version=1 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 @@ -70,7 +70,7 @@ org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false -org.eclipse.jdt.core.formatter.indentation.size=2 +org.eclipse.jdt.core.formatter.indentation.size=4 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert @@ -255,6 +255,6 @@ org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=space -org.eclipse.jdt.core.formatter.tabulation.size=2 +org.eclipse.jdt.core.formatter.tabulation.size=4 org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true diff -r 5d205e48f9d3 -r 30ef4c917204 org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/Activator.java --- a/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/Activator.java Mon Feb 22 15:46:49 2010 -0800 +++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/Activator.java Tue Feb 23 13:23:31 2010 -0800 @@ -24,6 +24,7 @@ import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; +import org.symbian.tools.wrttools.debug.internal.launch.ChromeInstancesManager; /** * The activator class controls the plug-in life cycle @@ -42,6 +43,8 @@ // The shared instance private static Activator plugin; + + private final ChromeInstancesManager chromes = new ChromeInstancesManager(); /** * The constructor @@ -64,6 +67,7 @@ */ public void stop(BundleContext context) throws Exception { plugin = null; + chromes.shutdown(); super.stop(context); } @@ -76,6 +80,10 @@ return plugin; } + public ChromeInstancesManager getChromeInstancesManager() { + return chromes; + } + public static void log(Throwable e) { log(e.getLocalizedMessage(), e); } diff -r 5d205e48f9d3 -r 30ef4c917204 org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/ChromeInstancesManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/ChromeInstancesManager.java Tue Feb 23 13:23:31 2010 -0800 @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2009 Symbian Foundation and/or its subsidiary(-ies). + * All rights reserved. + * This component and the accompanying materials are made available + * under the terms of the License "Eclipse Public License v1.0" + * which accompanies this distribution, and is available + * at the URL "http://www.eclipse.org/legal/epl-v10.html". + * + * Initial Contributors: + * Symbian Foundation - initial contribution. + * Contributors: + * Description: + * Overview: + * Details: + * Platforms/Drives/Compatibility: + * Assumptions/Requirement/Pre-requisites: + * Failures and causes: + *******************************************************************************/ +package org.symbian.tools.wrttools.debug.internal.launch; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.symbian.tools.wrttools.debug.internal.Activator; +import org.symbian.tools.wrttools.debug.internal.ChromeDebugUtils; +import org.symbian.tools.wrttools.util.CoreUtil; + +public class ChromeInstancesManager { + private static final String[] CHROME_ARGS = { "\"%s\"", "--remote-shell-port=%d", // Here we will set port + "\"--user-data-dir=%s\"", // Here we will set profile folder so user settings have no effect + "\"--disk-cache-dir=%s\"", // We don't care + "--disable-web-security", // Widgets can use network now + "--disable-extenions", // Use standard UI, should also improve speed and stability + "--disable-plugins", // Run faster! + "--always-enable-dev-tools", "--no-default-browser-check", // Our users don't need this nagging + "--no-first-run", // We don't care + "--app=%s" // Here we will have widget URI as --app argument + }; + private final Map chromes = Collections.synchronizedMap(new HashMap()); + + private static final int EXECUTIBLE_INDEX = 0; + private static final int PORT_INDEX = 1; + private static final int USER_DATA_INDEX = 2; + private static final int CACHE_INDEX = 3; + private static final int URL_INDEX = CHROME_ARGS.length - 1; + + private int profileNum = 0; + + public void startChrome(final Object key, int port, final String url) throws CoreException { + final String browserExecutable = ChromeDebugUtils.getChromeExecutible(); + if (browserExecutable == null) { + throw createCoreException("No Chrome browser available", null); + } + + String[] commandline = new String[CHROME_ARGS.length]; + System.arraycopy(CHROME_ARGS, 0, commandline, 0, CHROME_ARGS.length); + commandline[EXECUTIBLE_INDEX] = String.format(CHROME_ARGS[EXECUTIBLE_INDEX], browserExecutable); + commandline[PORT_INDEX] = String.format(CHROME_ARGS[PORT_INDEX], port); + commandline[USER_DATA_INDEX] = String.format(CHROME_ARGS[USER_DATA_INDEX], getChromeProfilePath()); + commandline[CACHE_INDEX] = String.format(CHROME_ARGS[CACHE_INDEX], getChromeCachePath()); + commandline[URL_INDEX] = String.format(CHROME_ARGS[URL_INDEX], url); + + // 2. Start Chrome + try { + Process process = Runtime.getRuntime().exec(commandline); + chromes.put(key, process); + } catch (IOException e) { + StringBuilder builder = new StringBuilder(); + for (String string : commandline) { + builder.append(" ").append(string); + } + throw createCoreException("Cannot execute: {0}", builder.toString().trim(), e); + } + + } + + private String getChromeCachePath() { + return getChromeSpecialDir(".chromecache"); + } + + /** + * Terminate Chrome instance associated with given key. + */ + public synchronized void stopChrome(final Object key) { + + } + + public synchronized void forgetChrome(final Object key) { + + } + + public synchronized void shutdown() { + String dir = getChromeSpecialDir(""); + File directory = new File(dir); + File[] files = directory.listFiles(new FileFilter() { + public boolean accept(File pathname) { + return pathname.isDirectory() && pathname.getName().matches("\\.chr\\d{3}") + && !isChromeRunning(pathname); + } + }); + boolean removedAll = true; + for (File file : files) { + removedAll = delete(file) && removedAll; + } + if (removedAll) { + String cachePath = getChromeCachePath(); + delete(new File(cachePath)); + } + + } + + private boolean delete(File file) { + if (!file.exists()) { + return true; + } else if (file.isDirectory()) { + File[] files = file.listFiles(); + for (File f : files) { + if (!delete(f)) { + return false; + } + } + } + return file.delete(); + } + + private CoreException createCoreException(String pattern, String arg, Throwable exeption) { + return createCoreException(MessageFormat.format(pattern, arg), exeption); + } + + private CoreException createCoreException(String message, Throwable exeption) { + return new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, exeption)); + } + + private String getChromeProfilePath() { + while (true) { + String dir = getChromeSpecialDir(String.format(".chr%03d", profileNum++)); + if (!new File(dir).exists()) { + return dir; + } + } + } + + private boolean isChromeRunning(File pathname) { + File file = new File(pathname, "Default/Cookies"); + try { + // Note: it is ok to delete cookies file - if it can be deleted then Chrome is not running. + // If Chrome is running then we will not be able to delete the file. + // We do not need to preserve state between launches. So it is ok to delete coockies. + return file.exists() && !file.delete(); + } catch (Exception e) { + Activator.log(e); + return true; + } + } + + private String getChromeSpecialDir(String subdir) { + IPath location = ResourcesPlugin.getWorkspace().getRoot().getLocation(); + if (CoreUtil.isLinux() && location.toString().length() > 50) { + location = new Path(System.getProperty("user.home")).append(".wrtdebug"); + } + return location.append(subdir).toOSString(); + } +} diff -r 5d205e48f9d3 -r 30ef4c917204 org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/DebugConnectionJob.java --- a/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/DebugConnectionJob.java Mon Feb 22 15:46:49 2010 -0800 +++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/DebugConnectionJob.java Tue Feb 23 13:23:31 2010 -0800 @@ -32,6 +32,7 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.symbian.tools.wrttools.debug.internal.Activator; @@ -70,10 +71,10 @@ } public boolean browserRunning(URI uri) throws CoreException { - JavascriptVmEmbedder.ConnectionToRemote remoteServer = createConnectionToRemote( - port, launch, uri); DestructingGuard destructingGuard = new DestructingGuard(); try { + JavascriptVmEmbedder.ConnectionToRemote remoteServer = createConnectionToRemote( + port, launch, uri); Destructable lauchDestructor = new Destructable() { public void destruct() { if (!launch.hasChildren()) { @@ -82,12 +83,10 @@ } } }; - destructingGuard.addValue(lauchDestructor); WorkspaceBridge.Factory bridgeFactory = new WRTProjectWorkspaceBridge.Factory( project); - final DebugTargetImpl target = new DebugTargetImpl(launch, bridgeFactory); @@ -109,6 +108,9 @@ // All OK destructingGuard.discharge(); + } catch (CoreException e) { + DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch); + throw e; } finally { destructingGuard.doFinally(); } diff -r 5d205e48f9d3 -r 30ef4c917204 org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/PortPolicy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/PortPolicy.java Tue Feb 23 13:23:31 2010 -0800 @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2009 Symbian Foundation and/or its subsidiary(-ies). + * All rights reserved. + * This component and the accompanying materials are made available + * under the terms of the License "Eclipse Public License v1.0" + * which accompanies this distribution, and is available + * at the URL "http://www.eclipse.org/legal/epl-v10.html". + * + * Initial Contributors: + * Symbian Foundation - initial contribution. + * Contributors: + * Description: + * Overview: + * Details: + * Platforms/Drives/Compatibility: + * Assumptions/Requirement/Pre-requisites: + * Failures and causes: + *******************************************************************************/ +package org.symbian.tools.wrttools.debug.internal.launch; + +import java.io.IOException; +import java.net.ServerSocket; + +import org.symbian.tools.wrttools.debug.internal.Activator; + +public abstract class PortPolicy { + private static class ReuseSamePort extends PortPolicy { + private int port = -1; + + @Override + protected int getPort() { + if (port < 0) { + port = getOpenPort(); + } + return port; + } + } + + private static class NewPortEachTime extends PortPolicy { + @Override + protected int getPort() { + return getOpenPort(); + } + } + + public static final PortPolicy INSTANCE; + static { + // if (CoreUtil.isMac()) { + INSTANCE = new NewPortEachTime(); + // } else { + // INSTANCE = new ReuseSamePort(); + // } + } + + public static synchronized int getPortNumber() { + return INSTANCE.getPort(); + } + + public int getOpenPort() { + try { + final ServerSocket socket = new ServerSocket(0); + int port = socket.getLocalPort(); + socket.close(); + return port; + } catch (IOException e) { + Activator.log(e); + return 7222; + } + } + + protected abstract int getPort(); +} diff -r 5d205e48f9d3 -r 30ef4c917204 org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/WidgetLaunchDelegate.java --- a/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/WidgetLaunchDelegate.java Mon Feb 22 15:46:49 2010 -0800 +++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/WidgetLaunchDelegate.java Tue Feb 23 13:23:31 2010 -0800 @@ -18,18 +18,14 @@ *******************************************************************************/ package org.symbian.tools.wrttools.debug.internal.launch; -import java.io.IOException; -import java.net.ServerSocket; import java.net.URI; import java.text.MessageFormat; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; @@ -37,120 +33,51 @@ import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.model.ILaunchConfigurationDelegate; import org.symbian.tools.wrttools.debug.internal.Activator; -import org.symbian.tools.wrttools.debug.internal.ChromeDebugUtils; import org.symbian.tools.wrttools.debug.internal.IConstants; import org.symbian.tools.wrttools.previewer.PreviewerPlugin; -import org.symbian.tools.wrttools.util.CoreUtil; -public class WidgetLaunchDelegate implements - ILaunchConfigurationDelegate { +public class WidgetLaunchDelegate implements ILaunchConfigurationDelegate { public static final String ID = "org.symbian.tools.wrttools.debug.widget"; - private static final String[] CHROME_ARGS = { - "executable-placeholder", // Chrome executable. Configurable in preferences - "port-placeholder", // Here we will set port - "profile-placeholder", // Here we will set profile folder so user settings have no effect - "--disable-web-security", // Widgets can use network now - "--disable-extenions", // Use standard UI, should also re - "--disable-plugins", // Run faster! - "--no-default-browser-check", // Our users don't need this nagging - "--no-first-run", // We don't care - "widget-placeholder" // Here we will have widget URI as --app argument - }; - private static final int EXECUTABLE_ARG_NUM = 0; - private static final int PORT_ARG_NUM = 1; - private static final int PROFILE_ARG_NUM = 2; - private static final int APP_ARG_NUM = CHROME_ARGS.length - 1; - - public void launch(ILaunchConfiguration configuration, String mode, - final ILaunch launch, IProgressMonitor monitor) + + public void launch(ILaunchConfiguration configuration, String mode, final ILaunch launch, IProgressMonitor monitor) throws CoreException { monitor.beginTask("Preparing WRT Debugger", IProgressMonitor.UNKNOWN); - // 1. Load all parameters - IProject project = getProject(configuration); ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager(); - - if (isProjectDebugged(project, launchManager, launch)) { - showProjectIsDebugged(); - launchManager.removeLaunch(launch); - throw createCoreException(MessageFormat.format("Project {0} is already running.", project.getName()), null); - } - - int port = findFreePort(); boolean debug = mode.equals(ILaunchManager.DEBUG_MODE); - final URI uri = prepareDebugger(project, debug, launch, port); - final String browserExecutable = ChromeDebugUtils.getChromeExecutible(); - if (browserExecutable == null) { - launchManager.removeLaunch(launch); - throw createCoreException("No Chrome browser available", null); - } + try { + // 1. Load all parameters + IProject project = getProject(configuration); + isProjectDebugged(project, launchManager, launch); - // 2. Start Chrome - synchronized (CHROME_ARGS) { // No chances for collision. Still, better safe then spend several days looking for hard-to-reproduce problem - CHROME_ARGS[EXECUTABLE_ARG_NUM] = browserExecutable; - CHROME_ARGS[PROFILE_ARG_NUM] = "--user-data-dir=\"" + getChromeProfilePath() + "\""; - CHROME_ARGS[PORT_ARG_NUM] = "--remote-shell-port=" + port; - CHROME_ARGS[APP_ARG_NUM] = MessageFormat.format("--app={0}", uri.toASCIIString()); - try { - Runtime.getRuntime().exec(CHROME_ARGS, null, null); - } catch (IOException e) { - launchManager.removeLaunch(launch); - StringBuffer commandLine = new StringBuffer(CHROME_ARGS[0]); - for (int i = 1; i < CHROME_ARGS.length; i++) { - commandLine.append(" ").append(CHROME_ARGS[i]); - } - throw createCoreException("Cannot execute: {0}", commandLine - .toString(), e); - } + int port = PortPolicy.getPortNumber(); + final URI uri = prepareDebugger(project, debug, launch, port); + + Activator.getDefault().getChromeInstancesManager().startChrome(launch, port, uri.toASCIIString()); + } catch (CoreException e) { + launchManager.removeLaunch(launch); + throw e; } - if (!debug) { launchManager.removeLaunch(launch); } monitor.done(); } - - private String getChromeProfilePath() { - IPath location = ResourcesPlugin.getWorkspace().getRoot().getLocation(); - if (CoreUtil.isLinux() && location.toString().length() > 50) { - location = new Path(System.getProperty("user.home")).append(".wrtdebug"); - } - return location.append(".chrome").toOSString(); - } - - - private int findFreePort() { - try { - final ServerSocket socket = new ServerSocket(0); - int port = socket.getLocalPort(); - socket.close(); - return port; - } catch (IOException e) { - Activator.log(e); - return 7222; - } - } - - - private void showProjectIsDebugged() { - } - - - private boolean isProjectDebugged(IProject project, ILaunchManager launchManager, ILaunch l) throws CoreException { + private void isProjectDebugged(IProject project, ILaunchManager launchManager, ILaunch l) throws CoreException { ILaunch[] launches = launchManager.getLaunches(); for (ILaunch launch : launches) { ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration(); if (!l.equals(launch) && ID.equals(launchConfiguration.getType().getIdentifier())) { IProject p2 = getProject(launchConfiguration); - return project.equals(p2); + if (project.equals(p2)) { + throw createCoreException(MessageFormat + .format("Project {0} is already running.", project.getName()), null); + } } } - return false; } - - private URI prepareDebugger(IProject project, boolean debug, - final ILaunch launch, final int port) { + private URI prepareDebugger(IProject project, boolean debug, final ILaunch launch, final int port) { if (debug) { final DebugConnectionJob job = new DebugConnectionJob(project, port, launch); return PreviewerPlugin.getDefault().getHttpPreviewer().previewProject(project, job); @@ -159,31 +86,20 @@ } } - - private IProject getProject(ILaunchConfiguration configuration) - throws CoreException { - String projectName = configuration.getAttribute( - IConstants.PROP_PROJECT_NAME, (String) null); + private IProject getProject(ILaunchConfiguration configuration) throws CoreException { + String projectName = configuration.getAttribute(IConstants.PROP_PROJECT_NAME, (String) null); if (projectName == null) { throw createCoreException("Project is not selected", null); } - IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject( - projectName); + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); if (!project.isAccessible()) { - throw createCoreException(MessageFormat.format( - "Project {0} is not opened", projectName), null); + throw createCoreException(MessageFormat.format("Project {0} is not opened", projectName), null); } return project; } - private CoreException createCoreException(String message, String arg, - Throwable exeption) { - return createCoreException(MessageFormat.format(message, arg), exeption); - } - private CoreException createCoreException(String message, Throwable exeption) { - return new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, - message, exeption)); + return new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, exeption)); } } diff -r 5d205e48f9d3 -r 30ef4c917204 org.symbian.tools.wrttools.product/launch/WRT IDE Product (Windows).launch --- a/org.symbian.tools.wrttools.product/launch/WRT IDE Product (Windows).launch Mon Feb 22 15:46:49 2010 -0800 +++ b/org.symbian.tools.wrttools.product/launch/WRT IDE Product (Windows).launch Tue Feb 23 13:23:31 2010 -0800 @@ -1,4 +1,4 @@ - + @@ -22,473 +22,473 @@ - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + diff -r 5d205e48f9d3 -r 30ef4c917204 org.symbian.tools.wrttools.product/wrt-ide.product --- a/org.symbian.tools.wrttools.product/wrt-ide.product Mon Feb 22 15:46:49 2010 -0800 +++ b/org.symbian.tools.wrttools.product/wrt-ide.product Tue Feb 23 13:23:31 2010 -0800 @@ -55,6 +55,7 @@ +