View | Details | Raw Unified | Return to bug 190711 | Differences between
and this patch

Collapse All | Expand All

(-)META-INF/MANIFEST.MF (+1 lines)
Lines 112-115 Link Here
112
Import-Package: com.ibm.icu.text,
112
Import-Package: com.ibm.icu.text,
113
 org.eclipse.jdt.debug.core
113
 org.eclipse.jdt.debug.core
114
Bundle-RequiredExecutionEnvironment: J2SE-1.4
114
Bundle-RequiredExecutionEnvironment: J2SE-1.4
115
Service-Component: OSGI-INF/component.xml
115
Bundle-ActivationPolicy: lazy
116
Bundle-ActivationPolicy: lazy
(-)OSGI-INF/component.xml (+5 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" name="org.eclipse.pde.target">
3
   <implementation class="org.eclipse.pde.internal.ui.target.ExportTargetMetadata"/>
4
   <reference bind="bind" cardinality="1..1" interface="org.eclipse.equinox.p2.core.IProvisioningAgent" name="IMetadataRepositoryManager" policy="static" unbind="unbind"/>
5
</scr:component>
(-)plugin.properties (+1 lines)
Lines 77-82 Link Here
77
77
78
PluginSearchPage.label = Plug-in Search
78
PluginSearchPage.label = Plug-in Search
79
79
80
target.export.wizard.name=Target definition
80
PluginExportWizard.label=Deployable plug-ins and fragments
81
PluginExportWizard.label=Deployable plug-ins and fragments
81
PluginExportWizard.description=Export the selected plug-ins and/or fragments \
82
PluginExportWizard.description=Export the selected plug-ins and/or fragments \
82
in a form suitable for deploying in an Eclipse product.
83
in a form suitable for deploying in an Eclipse product.
(-)plugin.xml (+10 lines)
Lines 36-41 Link Here
36
      </perspective>
36
      </perspective>
37
   </extension>
37
   </extension>
38
   <extension
38
   <extension
39
         point="org.eclipse.ui.exportWizards">
40
      <wizard
41
            category="org.eclipse.pde.ui.PluginDevelopment"
42
            class="org.eclipse.pde.internal.ui.target.TargetDefinitionExportWizard"
43
            icon="icons/obj16/target_profile_xml_obj.gif"
44
            id="org.eclipse.pde.target.wizard"
45
            name="%target.export.wizard.name">
46
      </wizard>
47
   </extension>
48
   <extension
39
         point="org.eclipse.ui.preferencePages">
49
         point="org.eclipse.ui.preferencePages">
40
      <page
50
      <page
41
            name="%preferences.main.name"
51
            name="%preferences.main.name"
(-)src/org/eclipse/pde/internal/ui/PDEUIMessages.java (+14 lines)
Lines 1678-1683 Link Here
1678
	public static String CategorySection_newCategoryName;
1678
	public static String CategorySection_newCategoryName;
1679
	public static String CategorySection_newCategoryLabel;
1679
	public static String CategorySection_newCategoryLabel;
1680
1680
1681
	// Target Export ########################################
1682
	public static String ExportTargetDefinition_task;
1683
	public static String ExportTargetDeleteOldData;
1684
	public static String ExportTargetExportFeatures;
1685
	public static String ExportTargetExportPlugins;
1686
	public static String ExportActiveTargetDefinition;
1687
	public static String ExportTargetCurrentTarget;
1688
	public static String ExportTargetChooseFolder;
1689
	public static String ExportTargetBrowse;
1690
	public static String ExportTargetSelectDestination;
1691
	public static String ExportTargetSpecifyDestination;
1692
	public static String ExportTargetClearDestination;
1693
	public static String ExportTargetError_ChooseDestination;
1694
1681
	public static String CategoryDetails_title;
1695
	public static String CategoryDetails_title;
1682
	public static String CategoryDetails_sectionDescription;
1696
	public static String CategoryDetails_sectionDescription;
1683
	public static String CategoryDetails_name;
1697
	public static String CategoryDetails_name;
(-)src/org/eclipse/pde/internal/ui/pderesources.properties (+15 lines)
Lines 1553-1558 Link Here
1553
CategorySection_newCategoryName = new_category_{0}
1553
CategorySection_newCategoryName = new_category_{0}
1554
CategorySection_newCategoryLabel = New Category {0}
1554
CategorySection_newCategoryLabel = New Category {0}
1555
1555
1556
######### Target Export Wizard ###################################33
1557
ExportTargetDefinition_task = Exporting current target definition...
1558
ExportTargetDeleteOldData = Deleting old data...
1559
ExportTargetExportFeatures = Exporting features...
1560
ExportTargetExportPlugins = Exporting plugins...
1561
ExportActiveTargetDefinition = Export Active Target Definition
1562
ExportTargetCurrentTarget = Current Target Definition: 
1563
ExportTargetChooseFolder = Folder
1564
ExportTargetBrowse = Browse...
1565
ExportTargetSelectDestination = Select Destination
1566
ExportTargetSpecifyDestination = Specify the destination folder for the current target
1567
ExportTargetClearDestination = Clear destination directory before exporting
1568
ExportTargetError_ChooseDestination = Please choose a destination directory"
1569
1570
1556
CategoryDetails_title = Category Properties
1571
CategoryDetails_title = Category Properties
1557
CategoryDetails_sectionDescription = Provide a unique id, a name and a description for each category.\n\
1572
CategoryDetails_sectionDescription = Provide a unique id, a name and a description for each category.\n\
1558
"*" denotes a required field.
1573
"*" denotes a required field.
(-)src/org/eclipse/pde/internal/ui/target/ExportActiveTargetJob.java (+149 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009-2010 EclipseSource Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Chris Aniszczyk <zx@eclipsesource.com> - initial API and implementation
10
 *     Ian Bull <irbull@eclipsesource.com> - initial API and implementation
11
 *******************************************************************************/
12
package org.eclipse.pde.internal.ui.target;
13
14
import java.net.URI;
15
import org.eclipse.core.filesystem.*;
16
import org.eclipse.core.runtime.*;
17
import org.eclipse.core.runtime.jobs.Job;
18
import org.eclipse.equinox.p2.engine.IProfile;
19
import org.eclipse.pde.core.plugin.IPluginModelBase;
20
import org.eclipse.pde.core.plugin.PluginRegistry;
21
import org.eclipse.pde.internal.core.FeatureModelManager;
22
import org.eclipse.pde.internal.core.PDECore;
23
import org.eclipse.pde.internal.core.feature.ExternalFeatureModel;
24
import org.eclipse.pde.internal.core.ifeature.IFeatureModel;
25
import org.eclipse.pde.internal.core.target.TargetDefinition;
26
import org.eclipse.pde.internal.core.target.TargetPlatformService;
27
import org.eclipse.pde.internal.ui.PDEPlugin;
28
import org.eclipse.pde.internal.ui.PDEUIMessages;
29
30
/**
31
 * This job exports the bundles and features that make up your target. 
32
 *
33
 */
34
public class ExportActiveTargetJob extends Job {
35
36
	private URI fDestination;
37
	private boolean fclearDestinationDirectory = false;
38
39
	public ExportActiveTargetJob(URI destination, boolean clearDestinationDirectory) {
40
		super("Export Current Target Definition Job"); //$NON-NLS-1$
41
		fDestination = destination;
42
		fclearDestinationDirectory = clearDestinationDirectory;
43
	}
44
45
	protected IStatus run(IProgressMonitor monitor) {
46
47
		IFileSystem fileSystem = EFS.getLocalFileSystem();
48
		if (!fileSystem.canWrite()) {
49
			return new Status(IStatus.ERROR, PDEPlugin.getPluginId(), "Destination directory not writable."); //$NON-NLS-1$ 
50
		}
51
		IFileStore destination = fileSystem.getStore(fDestination);
52
53
		FeatureModelManager featureManager = PDECore.getDefault().getFeatureModelManager();
54
		IFeatureModel[] featureModels = featureManager.getModels();
55
		IPluginModelBase[] pluginModels = PluginRegistry.getExternalModels();
56
57
		IFileStore featureDir = destination.getChild("features"); //$NON-NLS-1$
58
		IFileStore pluginDir = destination.getChild("plugins"); //$NON-NLS-1$
59
		IFileStore metadataXML = destination.getChild("content.xml"); //$NON-NLS-1$
60
		IFileStore metadataJAR = destination.getChild("content.jar"); //$NON-NLS-1$
61
62
		int totalWork = featureModels.length + pluginModels.length;
63
64
		try {
65
			monitor.beginTask(PDEUIMessages.ExportTargetDefinition_task, totalWork);
66
			if (fclearDestinationDirectory) {
67
				monitor.subTask(PDEUIMessages.ExportTargetDeleteOldData); //Deleting old data...
68
			}
69
70
			try {
71
				if (fclearDestinationDirectory) {
72
					ExportTargetMetadata.getDefault().clearExporedRepository(fDestination);
73
74
					if (featureDir.fetchInfo().exists()) {
75
						featureDir.delete(EFS.NONE, new NullProgressMonitor());
76
					}
77
					if (pluginDir.fetchInfo().exists()) {
78
						pluginDir.delete(EFS.NONE, new NullProgressMonitor());
79
					}
80
					if (metadataJAR.fetchInfo().exists()) {
81
						metadataJAR.delete(EFS.NONE, new NullProgressMonitor());
82
					}
83
					if (metadataXML.fetchInfo().exists()) {
84
						metadataXML.delete(EFS.NONE, new NullProgressMonitor());
85
					}
86
				}
87
88
				if (!featureDir.fetchInfo().exists()) {
89
					featureDir.mkdir(EFS.NONE, new NullProgressMonitor());
90
				}
91
				if (!pluginDir.fetchInfo().exists()) {
92
					pluginDir.mkdir(EFS.NONE, new NullProgressMonitor());
93
				}
94
			} catch (CoreException e1) {
95
				return new Status(IStatus.ERROR, PDEPlugin.getPluginId(), "Failed to create destination directory.", e1); //$NON-NLS-1$
96
			}
97
98
			monitor.subTask(PDEUIMessages.ExportTargetExportFeatures);
99
			for (int i = 0; i < featureModels.length; i++) {
100
				IFeatureModel model = featureModels[i];
101
				if (model.isEnabled() && model instanceof ExternalFeatureModel) {
102
					copy(model.getInstallLocation(), featureDir, fileSystem, monitor);
103
				}
104
			}
105
106
			monitor.subTask(PDEUIMessages.ExportTargetExportPlugins);
107
			for (int i = 0; i < pluginModels.length; i++) {
108
				IPluginModelBase model = pluginModels[i];
109
				//if (model.isEnabled()) {
110
				copy(model.getInstallLocation(), pluginDir, fileSystem, monitor);
111
				//}
112
			}
113
114
			try {
115
				IProfile profile = ((TargetDefinition) TargetPlatformService.getDefault().getWorkspaceTargetHandle().getTargetDefinition()).getProfile();
116
				ExportTargetMetadata component = ExportTargetMetadata.getDefault();
117
				IStatus status = component.exportMetadata(profile, fDestination, "Get target name plz"); //TODO: Get the target name //$NON-NLS-1$
118
				if (status.isOK())
119
					return status;
120
			} catch (CoreException e) {
121
				return new Status(IStatus.ERROR, PDEPlugin.getPluginId(), "Failed to export the target", e); //$NON-NLS-1$ 
122
			}
123
		} catch (CoreException e) {
124
			return new Status(IStatus.ERROR, PDEPlugin.getPluginId(), "Failed to export the target", e); //$NON-NLS-1$ 
125
		}
126
127
		finally {
128
			monitor.done();
129
		}
130
		return Status.OK_STATUS;
131
	}
132
133
	private IStatus copy(String src, IFileStore destinationParent, IFileSystem fileSystem, IProgressMonitor monitor) throws CoreException {
134
		Path srcPath = new Path(src);
135
		IFileStore source = fileSystem.getStore(srcPath);
136
		String elementName = srcPath.segment(srcPath.segmentCount() - 1);
137
		IFileStore destinationDirectory = destinationParent.getChild(elementName);
138
		if (destinationDirectory.fetchInfo().exists()) {
139
			monitor.worked(1);
140
			return Status.OK_STATUS;
141
		}
142
		if (source.fetchInfo().isDirectory()) {
143
			destinationDirectory.mkdir(EFS.NONE, new NullProgressMonitor());
144
		}
145
		source.copy(destinationDirectory, EFS.OVERWRITE, new SubProgressMonitor(monitor, 1));
146
		return Status.OK_STATUS;
147
	}
148
149
}
(-)src/org/eclipse/pde/internal/ui/target/ExportTargetMetadata.java (+99 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009-2010 EclipseSource Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Ian Bull <irbull@eclipsesource.com> - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.target;
12
13
import java.net.URI;
14
import org.eclipse.core.runtime.*;
15
import org.eclipse.equinox.p2.core.IProvisioningAgent;
16
import org.eclipse.equinox.p2.core.ProvisionException;
17
import org.eclipse.equinox.p2.engine.IProfile;
18
import org.eclipse.equinox.p2.query.IQueryResult;
19
import org.eclipse.equinox.p2.query.QueryUtil;
20
import org.eclipse.equinox.p2.repository.IRepositoryManager;
21
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
22
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
23
import org.eclipse.pde.internal.ui.PDEPlugin;
24
25
public class ExportTargetMetadata {
26
27
	IProvisioningAgent agent = null;
28
	public static ExportTargetMetadata instance = null;
29
30
	public void start() {
31
		instance = this;
32
	}
33
34
	public void stop() {
35
		instance = null;
36
37
	}
38
39
	public static ExportTargetMetadata getDefault() {
40
		return instance;
41
	}
42
43
	public synchronized void clearExporedRepository(URI destination) {
44
		if (agent == null)
45
			return;
46
		if (((IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME)).contains(destination))
47
			((IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME)).removeRepository(destination);
48
	}
49
50
	public synchronized IStatus exportMetadata(IProfile profile, URI destination, String targetName) {
51
		if (agent == null)
52
			return new Status(IStatus.ERROR, PDEPlugin.getPluginId(), "Failed to mirror the metadata."); //$NON-NLS-1$
53
		boolean removeRepoAfterLoad = false;
54
		try {
55
			IMetadataRepository repository = null;
56
57
			try {
58
				//TODO: There appears to be a small (5 byte) difference from when I do the load vs. the create
59
				//      The create gives the repo a version 1, while the load gives it 1.0.0
60
				//      this might be worth looking into
61
				removeRepoAfterLoad = !((IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME)).contains(destination);
62
				repository = ((IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME)).loadRepository(destination, IRepositoryManager.REPOSITORY_HINT_MODIFIABLE, new NullProgressMonitor());
63
			} catch (ProvisionException e) {
64
				// The repository cannot be loaded
65
			}
66
			if (repository == null) {
67
				repository = ((IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME)).createRepository(destination, targetName, IMetadataRepositoryManager.TYPE_SIMPLE_REPOSITORY, null);
68
			}
69
70
			if (repository != null) {
71
				mirrorMetadata(profile, repository);
72
			} else {
73
				return new Status(IStatus.ERROR, PDEPlugin.getPluginId(), "Failed to mirror the metadata."); //$NON-NLS-1$
74
			}
75
76
		} catch (ProvisionException e) {
77
			return new Status(IStatus.ERROR, PDEPlugin.getPluginId(), "Failed to mirror the metadata.", e); //$NON-NLS-1$
78
		} finally {
79
			if (removeRepoAfterLoad) {
80
				((IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME)).removeRepository(destination);
81
			}
82
		}
83
84
		return Status.OK_STATUS;
85
	}
86
87
	private void mirrorMetadata(IProfile profile, IMetadataRepository repository) {
88
		IQueryResult results = profile.query(QueryUtil.createIUAnyQuery(), new NullProgressMonitor());
89
		repository.addInstallableUnits(results.toUnmodifiableSet());
90
	}
91
92
	public void bind(IProvisioningAgent agent) {
93
		this.agent = agent;
94
	}
95
96
	public synchronized void unbind(IProvisioningAgent agent) {
97
		this.agent = null;
98
	}
99
}
(-)src/org/eclipse/pde/internal/ui/target/TargetDefinitionExportWizard.java (+51 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009-2010 EclipseSource Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Chris Aniszczyk <zx@eclipsesource.com> - initial API and implementation
10
 *     Ian Bull <irbull@eclipsesource.com> - initial API and implementation
11
 *******************************************************************************/
12
package org.eclipse.pde.internal.ui.target;
13
14
import java.io.File;
15
import org.eclipse.core.runtime.jobs.Job;
16
import org.eclipse.jface.viewers.IStructuredSelection;
17
import org.eclipse.jface.wizard.Wizard;
18
import org.eclipse.pde.internal.ui.PDEUIMessages;
19
import org.eclipse.ui.IExportWizard;
20
import org.eclipse.ui.IWorkbench;
21
22
public class TargetDefinitionExportWizard extends Wizard implements IExportWizard {
23
24
	private TargetDefinitionExportWizardPage fPage = null;
25
26
	public TargetDefinitionExportWizard() {
27
		setNeedsProgressMonitor(true);
28
		setWindowTitle(PDEUIMessages.ExportActiveTargetDefinition);
29
	}
30
31
	public void addPages() {
32
		fPage = new TargetDefinitionExportWizardPage();
33
		addPage(fPage);
34
	}
35
36
	public boolean performFinish() {
37
		String destDir = fPage.getDestinationDirectory();
38
		boolean clearDestDir = fPage.isClearDestinationDirectory();
39
		File file = new File(destDir);
40
41
		Job job = new ExportActiveTargetJob(file.toURI(), clearDestDir);
42
		job.schedule(200);
43
44
		return true;
45
	}
46
47
	public void init(IWorkbench workbench, IStructuredSelection selection) {
48
		// do nothing atm
49
	}
50
51
}
(-)src/org/eclipse/pde/internal/ui/target/TargetDefinitionExportWizardPage.java (+120 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009-2010 EclipseSource Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Chris Aniszczyk <zx@eclipsesource.com> - initial API and implementation
10
 *     Ian Bull <irbull@eclipsesource.com> - initial API and implementation
11
 *******************************************************************************/
12
package org.eclipse.pde.internal.ui.target;
13
14
import org.eclipse.core.runtime.IStatus;
15
import org.eclipse.jface.dialogs.Dialog;
16
import org.eclipse.jface.wizard.WizardPage;
17
import org.eclipse.pde.internal.ui.PDEUIMessages;
18
import org.eclipse.swt.SWT;
19
import org.eclipse.swt.events.*;
20
import org.eclipse.swt.layout.GridData;
21
import org.eclipse.swt.layout.GridLayout;
22
import org.eclipse.swt.widgets.*;
23
24
public class TargetDefinitionExportWizardPage extends WizardPage {
25
26
	private static final String PAGE_ID = "org.eclipse.pde.target.exportPage"; //$NON-NLS-1$
27
	private Button browseButton = null;
28
	private Text destDirText = null;
29
	private Button clearDestinationDirCheck = null;
30
31
	protected TargetDefinitionExportWizardPage() {
32
		super(PAGE_ID);
33
		setPageComplete(false);
34
		setTitle(PDEUIMessages.ExportActiveTargetDefinition);
35
		// TODO setImage(...)
36
	}
37
38
	public void createControl(Composite parent) {
39
		Composite container = new Composite(parent, SWT.NONE);
40
		GridLayout layout = new GridLayout(1, false);
41
		container.setLayout(layout);
42
		createExportDirectoryControl(container);
43
44
		//TODO initSettings();
45
46
		Dialog.applyDialogFont(container);
47
		setControl(container);
48
		setPageComplete(validate());
49
	}
50
51
	private void createExportDirectoryControl(Composite parent) {
52
		parent.setLayout(new GridLayout(3, false));
53
		parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
54
		new Label(parent, SWT.NONE).setText(PDEUIMessages.ExportTargetCurrentTarget);
55
		Label l = new Label(parent, SWT.NONE);
56
57
		// TODO zx can you get the name of the current target here?
58
		l.setText("get name of current target plz");
59
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
60
		gd.horizontalSpan = 2;
61
		l.setLayoutData(gd);
62
		new Label(parent, SWT.NONE).setText(PDEUIMessages.ExportTargetChooseFolder);
63
64
		destDirText = new Text(parent, SWT.BORDER);
65
		destDirText.setEditable(false);
66
		destDirText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
67
		destDirText.addModifyListener(new ModifyListener() {
68
			public void modifyText(ModifyEvent e) {
69
				controlChanged();
70
			}
71
		});
72
		browseButton = new Button(parent, SWT.PUSH);
73
		browseButton.setText(PDEUIMessages.ExportTargetBrowse);
74
		browseButton.addSelectionListener(new SelectionAdapter() {
75
			public void widgetSelected(SelectionEvent e) {
76
				DirectoryDialog dialog = new DirectoryDialog(getShell());
77
				dialog.setText(PDEUIMessages.ExportTargetSelectDestination);
78
				dialog.setMessage(PDEUIMessages.ExportTargetSpecifyDestination);
79
				String dir = destDirText.getText();
80
				dialog.setFilterPath(dir);
81
				dir = dialog.open();
82
				if (dir == null || dir.equals("")) { //$NON-NLS-1$
83
					return;
84
				}
85
				destDirText.setText(dir);
86
				controlChanged();
87
			}
88
		});
89
90
		clearDestinationDirCheck = new Button(parent, SWT.CHECK);
91
		clearDestinationDirCheck.setText(PDEUIMessages.ExportTargetClearDestination);
92
		gd = new GridData();
93
		gd.horizontalSpan = 2;
94
		clearDestinationDirCheck.setLayoutData(gd);
95
	}
96
97
	public String getDestinationDirectory() {
98
		return destDirText.getText();
99
	}
100
101
	public boolean isClearDestinationDirectory() {
102
		return clearDestinationDirCheck.getSelection();
103
	}
104
105
	public void controlChanged() {
106
		setPageComplete(validate());
107
	}
108
109
	protected boolean validate() {
110
		setMessage(null);
111
112
		if (destDirText.getText().equals("")) { //$NON-NLS-1$
113
			setMessage(PDEUIMessages.ExportTargetError_ChooseDestination, IStatus.WARNING);
114
			return false;
115
		}
116
117
		return true;
118
	}
119
120
}

Return to bug 190711