Bug 190533 - NullPointerException when installing a feature via update site with a cascaded configuration area
Summary: NullPointerException when installing a feature via update site with a cascade...
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Update (deprecated - use Eclipse>Equinox>p2) (show other bugs)
Version: 3.3   Edit
Hardware: PC Windows XP
: P2 critical (vote)
Target Milestone: 3.3 RC4   Edit
Assignee: Platform-Update-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: contributed
Depends on:
Blocks:
 
Reported: 2007-06-01 14:45 EDT by Mark Melvin CLA
Modified: 2007-06-06 21:18 EDT (History)
3 users (show)

See Also:
pascal: review+
tjwatson: review+
jeffmcaffer: review+


Attachments
Patch fixing the issue (2.62 KB, patch)
2007-06-01 17:20 EDT, Mark Melvin CLA
no flags Details | Diff
New patch throwing exceptions instead of logging warnings (5.11 KB, patch)
2007-06-06 12:54 EDT, Mark Melvin CLA
no flags Details | Diff
New patch throwing exceptions instead of logging warnings (5.12 KB, patch)
2007-06-06 15:16 EDT, Thomas Watson CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Melvin CLA 2007-06-01 14:45:17 EDT
Build ID: I20070516-1800

I have a product that uses a shared configuration setup with a read-only, shared configuration area and a cascaded-style user configuration area.  This has never been set up correctly and I am just now understanding how all this works.  However, now that I have it set up correctly (at least I am pretty sure I do), I cannot install new features into my user-specific configuration area without the update system bailing with an NPE (and the feature is never installed).

Steps to reproduce (all as a power-user with admin privileges):

1. Install eclipse into some area.
2. Initialize this installed eclipse by running it, or running -initialize
3. Edit config.ini to contain the following lines:

# The default workspace location
osgi.instance.area.default=@user.home/workspace

# The user-writable configuration location
osgi.configuration.area=@user.home/.eclipse/configuration

# The shared (parent) configuration area
osgi.sharedConfiguration.area=platform:/base/configuration

# Ensure the shared, platform configuration location is read only
osgi.sharedConfiguration.area.readOnly=true

# Make the configuration area cascaded
osgi.configuration.area.cascaded=true

4. Now run eclipse again, and you should be have a user-specific configuration area that is cascaded with the install area.
5. Go to any update site and attempt to install a feature.  Make sure you leave the default location as %USER_HOME%/.eclipse/configuration
6. Watch it fail with an NPE.

More information:
Here is the error from the error log:

!ENTRY org.eclipse.core.jobs 4 2 2007-06-01 14:30:18.093
!MESSAGE An internal error occurred during: "Update Manager".
!STACK 0
java.lang.NullPointerException
	at org.eclipse.update.internal.core.InstallConfiguration.saveFeatureEntry(InstallConfiguration.java:527)
	at org.eclipse.update.internal.core.InstallConfiguration.save(InstallConfiguration.java:407)
	at org.eclipse.update.internal.core.LocalSite.save(LocalSite.java:190)
	at org.eclipse.update.internal.operations.BatchInstallOperation.execute(BatchInstallOperation.java:94)
	at org.eclipse.update.internal.ui.wizards.InstallWizard2.install(InstallWizard2.java:373)
	at org.eclipse.update.internal.ui.wizards.InstallWizard2.access$1(InstallWizard2.java:370)
	at org.eclipse.update.internal.ui.wizards.InstallWizard2$1.run(InstallWizard2.java:483)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

And here is the relevant info from my configuration dump:

eclipse.ee.install.verify=false
eclipse.product=com.amis.platform.ide
eclipse.startTime=1180722411921
eclipse.vm=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\bin\client\jvm.dll
eclipse.vmargs=-Xms40m
-Xmx256m
-XX:MaxPermSize=256m
-Djava.class.path=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\plugins\org.eclipse.equinox.launcher_1.0.0.v20070516.jar
eof=eof
file.encoding=Cp1252
file.encoding.pkg=sun.io
file.separator=\
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.awt.printerjob=sun.awt.windows.WPrinterJob
java.class.path=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\plugins\org.eclipse.equinox.launcher_1.0.0.v20070516.jar
java.class.version=49.0
java.endorsed.dirs=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\lib\endorsed
java.ext.dirs=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\lib\ext
java.home=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre
java.io.tmpdir=C:\DOCUME~1\MMELVI~1.AMI\LOCALS~1\Temp\
java.library.path=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse;.;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\PROGRA~1\DSPFAC~1\ADE11\bin;C:\Python23;C:\Program Files\UltraEdit;C:\programs\perl\sieperl\perl\5.8.0\bin;C:\programs\perl\sieperl\perl\5.8.0\bin\MSWin32-x86-perlio;c:\programs\bin;C:\programs\bin\cvsnt;C:\MinGW\bin;C:\programs\bin\ant1_7_0\bin;C:\Program Files\Zutubi\Pulse Developer Tools\bin;C:\Program Files\QuickTime\QTSystem\;C:\Cygwin\bin;C:\Cygwin\usr\local\bin;;C:\Program Files\AMIS\SignaKlara Tools 4\bin
java.runtime.name=Java(TM) 2 Runtime Environment, Standard Edition
java.runtime.version=1.5.0_06-b05
java.specification.name=Java Platform API Specification
java.specification.vendor=Sun Microsystems Inc.
java.specification.version=1.5
java.vendor=Sun Microsystems Inc.
java.vendor.url=http://java.sun.com/
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi
java.version=1.5.0_06
java.vm.info=mixed mode
java.vm.name=Java HotSpot(TM) Client VM
java.vm.specification.name=Java Virtual Machine Specification
java.vm.specification.vendor=Sun Microsystems Inc.
java.vm.specification.version=1.0
java.vm.vendor=Sun Microsystems Inc.
java.vm.version=1.5.0_06-b05
line.separator=

org.eclipse.equinox.launcher.splash.handle=3014976
org.eclipse.equinox.launcher.splash.location=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\\plugins\com.amis.platform_2.1.0.v20070518\splash.bmp
org.osgi.framework.executionenvironment=OSGi/Minimum-1.0,OSGi/Minimum-1.1,JRE-1.1,J2SE-1.2,J2SE-1.3,J2SE-1.4,J2SE-1.5
org.osgi.framework.language=en
org.osgi.framework.os.name=WindowsXP
org.osgi.framework.os.version=5.1
org.osgi.framework.processor=x86
org.osgi.framework.system.packages=javax.accessibility,javax.activity,javax.crypto,javax.crypto.interfaces,javax.crypto.spec,javax.imageio,javax.imageio.event,javax.imageio.metadata,javax.imageio.plugins.bmp,javax.imageio.plugins.jpeg,javax.imageio.spi,javax.imageio.stream,javax.management,javax.management.loading,javax.management.modelmbean,javax.management.monitor,javax.management.openmbean,javax.management.relation,javax.management.remote,javax.management.remote.rmi,javax.management.timer,javax.naming,javax.naming.directory,javax.naming.event,javax.naming.ldap,javax.naming.spi,javax.net,javax.net.ssl,javax.print,javax.print.attribute,javax.print.attribute.standard,javax.print.event,javax.rmi,javax.rmi.CORBA,javax.rmi.ssl,javax.security.auth,javax.security.auth.callback,javax.security.auth.kerberos,javax.security.auth.login,javax.security.auth.spi,javax.security.auth.x500,javax.security.cert,javax.security.sasl,javax.sound.midi,javax.sound.midi.spi,javax.sound.sampled,javax.sound.sampled.spi,javax.sql,javax.sql.rowset,javax.sql.rowset.serial,javax.sql.rowset.spi,javax.swing,javax.swing.border,javax.swing.colorchooser,javax.swing.event,javax.swing.filechooser,javax.swing.plaf,javax.swing.plaf.basic,javax.swing.plaf.metal,javax.swing.plaf.multi,javax.swing.plaf.synth,javax.swing.table,javax.swing.text,javax.swing.text.html,javax.swing.text.html.parser,javax.swing.text.rtf,javax.swing.tree,javax.swing.undo,javax.transaction,javax.transaction.xa,javax.xml,javax.xml.datatype,javax.xml.namespace,javax.xml.parsers,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.sax,javax.xml.transform.stream,javax.xml.validation,javax.xml.xpath,org.ietf.jgss,org.omg.CORBA,org.omg.CORBA_2_3,org.omg.CORBA_2_3.portable,org.omg.CORBA.DynAnyPackage,org.omg.CORBA.ORBPackage,org.omg.CORBA.portable,org.omg.CORBA.TypeCodePackage,org.omg.CosNaming,org.omg.CosNaming.NamingContextExtPackage,org.omg.CosNaming.NamingContextPackage,org.omg.Dynamic,org.omg.DynamicAny,org.omg.DynamicAny.DynAnyFactoryPackage,org.omg.DynamicAny.DynAnyPackage,org.omg.IOP,org.omg.IOP.CodecFactoryPackage,org.omg.IOP.CodecPackage,org.omg.Messaging,org.omg.PortableInterceptor,org.omg.PortableInterceptor.ORBInitInfoPackage,org.omg.PortableServer,org.omg.PortableServer.CurrentPackage,org.omg.PortableServer.POAManagerPackage,org.omg.PortableServer.POAPackage,org.omg.PortableServer.portable,org.omg.PortableServer.ServantLocatorPackage,org.omg.SendingContext,org.omg.stub.java.rmi,org.w3c.dom,org.w3c.dom.bootstrap,org.w3c.dom.events,org.w3c.dom.ls,org.xml.sax,org.xml.sax.ext,org.xml.sax.helpers
org.osgi.framework.vendor=Eclipse
org.osgi.framework.version=1.4.0
org.osgi.supports.framework.extension=true
org.osgi.supports.framework.fragment=true
org.osgi.supports.framework.requirebundle=true
os.arch=x86
os.name=Windows XP
os.version=5.1
osgi.arch=x86
osgi.bundles=org.eclipse.equinox.common@2:start, org.eclipse.update.configurator@3:start, org.eclipse.core.runtime@start
osgi.bundlestore=C:\Documents and Settings\MMELVIN.AMI_NT\.eclipse\configuration\org.eclipse.osgi\bundles
osgi.compatibility.bootdelegation=true
osgi.configuration.area=file:/C:/Documents and Settings/MMELVIN.AMI_NT/.eclipse/configuration/
osgi.configuration.area.cascaded=true
osgi.framework=file:/c:/Program Files/AMIS/SignaKlara Tools 4/eclipse/plugins/org.eclipse.osgi_3.3.0.v20070510.jar
osgi.framework.beginningstartlevel=1
osgi.framework.shape=jar
osgi.framework.version=3.3.0.v20070510
osgi.install.area=file:/C:/Program Files/AMIS/SignaKlara Tools 4/eclipse/
osgi.instance.area=file:/C:/Temp/workspaces/temp_workspace/
osgi.instance.area.default=file:/C:/Documents and Settings/MMELVIN.AMI_NT/workspace/
osgi.logfile=C:\Temp\workspaces\temp_workspace\.metadata\.log
osgi.manifest.cache=C:\Documents and Settings\MMELVIN.AMI_NT\.eclipse\configuration\org.eclipse.osgi\manifests
osgi.nl=en_US
osgi.os=win32
osgi.sharedConfiguration.area=file:/c:/Program Files/AMIS/SignaKlara Tools 4/eclipse/configuration/
osgi.sharedConfiguration.area.readOnly=true
osgi.splashLocation=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\\plugins\com.amis.platform_2.1.0.v20070518\splash.bmp
osgi.splashPath=platform:/base/plugins/com.amis.platform
osgi.syspath=c:\Program Files\AMIS\SignaKlara Tools 4\eclipse\plugins
osgi.ws=win32
path.separator=;
sun.arch.data.model=32
sun.boot.class.path=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\lib\rt.jar;C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\lib\i18n.jar;C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\lib\sunrsasign.jar;C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\lib\jsse.jar;C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\lib\jce.jar;C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\lib\charsets.jar;C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\classes
sun.boot.library.path=C:\Program Files\AMIS\SignaKlara Tools 4\eclipse\jre\bin
sun.cpu.endian=little
sun.cpu.isalist=pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86
sun.desktop=windows
sun.io.unicode.encoding=UnicodeLittle
sun.jnu.encoding=Cp1252
sun.management.compiler=HotSpot Client Compiler
sun.net.client.defaultConnectTimeout=60000
sun.net.client.defaultReadTimeout=60000
sun.os.patch.level=Service Pack 2
user.country=US
user.dir=C:\Program Files\AMIS\SignaKlara Tools 4
user.home=C:\Documents and Settings\MMELVIN.AMI_NT
user.language=en
user.name=MMELVIN
user.timezone=America/New_York
user.variant=

!STACK 0

java.lang.NullPointerException

	at org.eclipse.update.internal.core.InstallConfiguration.saveFeatureEntry(InstallConfiguration.java:527)

	at org.eclipse.update.internal.core.InstallConfiguration.save(InstallConfiguration.java:407)

	at org.eclipse.update.internal.core.LocalSite.save(LocalSite.java:190)

	at org.eclipse.update.internal.operations.BatchInstallOperation.execute(BatchInstallOperation.java:94)

	at org.eclipse.update.internal.ui.wizards.InstallWizard2.install(InstallWizard2.java:373)

	at org.eclipse.update.internal.ui.wizards.InstallWizard2.access$1(InstallWizard2.java:370)

	at org.eclipse.update.internal.ui.wizards.InstallWizard2$1.run(InstallWizard2.java:483)

	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
Comment 1 Dejan Glozic CLA 2007-06-01 14:55:55 EDT
Mark, while this NPE seems real, I don't see the fix happening in 3.3 considering we are trying to wrap the RC3 up today. If you do a bit of  debugging and possibly propose a patch that would fix the problem (or at least figure out what the problem is), it would increase the chances.
Comment 2 Mark Melvin CLA 2007-06-01 14:59:52 EDT
Working on it....
Comment 3 Mark Melvin CLA 2007-06-01 15:47:45 EDT
I feel kind of stupid asking this - but how can you debug something like this?  I can't seem to avoid the PDE completely destroying my intended configuration area setup.  It seems to generate a configuration area that is most definitely not cascaded even though it appears to be cascaded from the osgi.* properties set.

Any pointers on how to debug a development workspace with a cascaded configuration area?
Comment 4 Mark Melvin CLA 2007-06-01 16:11:22 EDT
Nevermind - I managed to connect as a remote Java app.
Comment 5 Dejan Glozic CLA 2007-06-01 16:22:37 EDT
Mark, the question is not stupid. Debugging Update is harder than the typical Eclipse self-hosting setup because PDE and Update fight for control. However, there is a way to set up selfhosting that will let Update lead. It is called 'feature-based self-hosting' and Update developer use it exclusively to test life cycle of features:

http://help.eclipse.org/help32/topic/org.eclipse.pde.doc.user/tips/pde_tips.htm

Look at the third top from the top.
Comment 6 Mark Melvin CLA 2007-06-01 17:20:41 EDT
Created attachment 69810 [details]
Patch fixing the issue

Here is a patch that fixes the issue.  In a nutshell, doing this:

URL featureUrl = new URL(cSite.getPlatformURLString());
siteEntry = (SiteEntry)runtimeConfiguration.findConfiguredSite(featureUrl);

Instead of this:

SiteEntry siteEntry = (SiteEntry)runtimeConfiguration.findConfiguredSite(cSite.getSite().getURL());

Fixes the null pointer.  But I must say that I am not sure this is a proper fix.  I just don't know enough about the whole update model to be sure.  What really scares me is that the code uses cSite.getSite().getURL() all over the place, which doesn't appear to do that same thing as cSite.getPlatformURLString().

Anyway, this passed my limited testing.  Perhaps someone with update model knowledge can confirm whether this is the right thing to do or not.
Comment 7 Mark Melvin CLA 2007-06-04 11:35:03 EDT
Some additional notes...  I noticed that I have been using the wrong property in my config.ini file - which is why our cascaded area never worked. I pasted this erroneous property in comment #1.  Anyway, the cascaded property *should* be osgi.configuration.cascaded (NOT osgi.configuration.area.cascaded).

At any rate, I have been trying to find a workaround for this because it looks like 3.3 is going to be broken in this regard.  I was originally specifying the shared config area using the "platform:/base/" URL, and it is this URL that update is choking on.  So, looking through the source for the launcher, it appears that not specifying a shared area at all will force it to be calculated from the install location.  Not setting this explicitly causes the platform to calculate it to the file:/ URL but unfortunately this still fails with a NPE.  

For completeness I have removed my shared config area declaration, and fixed up the property for cascading the config areas.  So, the bit you need to add to yoru config.ini file is *actually* as follows (replacing the information in comment #1):

# The default workspace location
osgi.instance.area.default=@user.home/workspace

# The user-writable configuration location
osgi.configuration.area=@user.home/.eclipse/configuration

# The shared (parent) configuration area
# Don't specify a value and let the platform calculate it from the install location
# osgi.sharedConfiguration.area=platform:/base/configuration

# Ensure the shared, platform configuration location is read only
osgi.sharedConfiguration.area.readOnly=true

# Make the configuration area cascaded
osgi.configuration.cascaded=true

But I still do not have a workaround.  I have also tried specifying a different install location when installing my plugins - but this does not work either.  It appears that specifying your configuration as "cascaded" basically breaks the platform making it impossible to install any plugins whatsoever.

For kicks I tried this out on Eclipse 3.2.2 and it also fails - but in a more colorful and even less useful manner.  You get all sorts of error dialogs when are attempting to install the new feature, right after you accept the license agreement when you need to select the installation location.  The table view showing the features to be installed (and their locations) is empty and clicking on the selected empty row causes more error dialogs (these are all NPEs in the error log).

So, this would seem to be a critical, blocking bug to me and I can't believe that this has not been discovered before this!  Is there any way to get people more knowlegable than me to look at it?
Comment 8 Mark Melvin CLA 2007-06-04 12:44:36 EDT
Looking through the mailing list archives (in particular here: http://dev.eclipse.org/mhonarc/lists/platform-update-dev/msg00701.html) I would think that there is no way this can be broken as bad as I am seeing it.  Is it possible I am doing something wrong here?   Is there any other info I can provide that will help figure out if I am failing to do something properly?
Comment 9 Dejan Glozic CLA 2007-06-04 14:50:15 EDT
Mark, I am afraid I am not too familiar with cascading configurations, particularly changes made in this area in order to keep up with the evolution of OSGi. I added Tom and Pascal in hope that they can shed some light on your problem.
Comment 10 Mark Melvin CLA 2007-06-04 17:12:36 EDT
Thanks, Dejan.  I have spent today looking at this again and I stand behind my patch more confidently now.  It looks like everywhere else that IPlatformConfiguration#findConfiguredSite is called, it is done using the following logic:

URL urlToGet = new URL(<something>.getPlatformURLString());
IPlatformConfiguration.findConfiguredSite(urlToGet);

However, in the specific case that was failing (the code I provided the patch for) it did not do it this way, rather it fed it the site URL directly.  I think this patch is good and should be considered.
Comment 11 Dejan Glozic CLA 2007-06-04 17:47:40 EDT
Mark, just to confirm: with this patch, can you use cascading configuration successfully? 

For the reviewers: see the comment 10.
Comment 12 Mark Melvin CLA 2007-06-04 19:39:26 EDT
Hi Dejan.  Yes.  After applying the patch I can sucessfully use a cascaded configuration and install plugins into the user-specific area (not the shared area) without errors.
Comment 13 Pascal Rapicault CLA 2007-06-05 16:22:54 EDT
The patch looks good and Mark has given good explanations as to why it should work. That said I'm not super familiar with the code and I have not run it. 
Overall I'm gonna give a +0.5 and you may want someone more familiar with the code (maybe even from the past) to take a look at it and provide another +0.5
Comment 14 Thomas Watson CLA 2007-06-05 17:35:06 EDT
I was able to reproduce the issue and verify the patch fixes the problem.  I would also like someone else to review the code that is more familiar with the codebase.
Comment 15 Dejan Glozic CLA 2007-06-05 18:25:43 EDT
Tom, that's the problem - we are the most familiar with the code, however that sounds (those who used to be familiar forgot it by now :-).
Comment 16 Thomas Watson CLA 2007-06-06 09:16:13 EDT
I looked at the code some more ... I agree with comment 10 by Mark it looks like all other the places findConfiguredSite is call use the following pattern.

URL urlToGet = new URL(<something>.getPlatformURLString());
IPlatformConfiguration.findConfiguredSite(urlToGet);

The approach looks good.  One question I have is why warn instead of throw CoreException when MalformedURLException and ClassCastException is thrown or when the siteEntry is null?  Should you not throw a CoreException?  In InstallConfiguration.savePluginPath the same logic is used except a new CoreException is thrown on MalformedURLExceptions and ClassCastExceptions
Comment 17 Dejan Glozic CLA 2007-06-06 11:12:01 EDT
Mark, can you reply to Tom's question? I would like to wrap up this bug today.
Comment 18 Mark Melvin CLA 2007-06-06 11:25:31 EDT
Regarding comment #16:

I guess when I was writing the patch I was a bit paranoid and in the mindset of "fix the problem, but if all else fails make it fall through to behave as if I didn't touch the code at all".  I guess that doesn't make a whole lot of sense; if you're going to fix it, fix it.  So I would have no problem changing those warnings to throw CoreExceptions similar to #savePluginPath.  This will result in a dialog being presented with a little more info than a simple NPE.

Do you want me to update the patch, or can you change those lines when you apply the changes?
Comment 19 Dejan Glozic CLA 2007-06-06 11:34:17 EDT
Please update the test and if possible make it fail to test the exception.
Comment 20 Mark Melvin CLA 2007-06-06 12:54:29 EDT
Created attachment 70365 [details]
New patch throwing exceptions instead of logging warnings

I have created a new patch.  I tested for failure by forcing exceptions and curiously enough nothing happened.  Some further debugging showed a couple spots where CoreExceptions were silently swallowed when installing.  I have fixed this up as well.  Please review as this now affects two files.
Comment 21 Thomas Watson CLA 2007-06-06 15:16:30 EDT
Created attachment 70398 [details]
New patch throwing exceptions instead of logging warnings

+1 to this patch

This is identical to the latest patch supplied by Mark except instead of using a hardcoded string "org.eclipse.update.core" it uses 
UpdateCore.getPlugin().getBundle().getSymbolicName()

For others reviewing the patch:  It took me a while to figure out that the extra catch for CoreExceptions in BatchInstallOperation.execute are the correct thing to do.  The original exception will be rethrown as the cause of an InvocationTargetException.  That exception will be used to display error status to the client/user.  We do not want to throw the CoreException which may occur while we are doing our best to recover from the original exception.
Comment 22 Dejan Glozic CLA 2007-06-06 15:33:10 EDT
Mark for Update committer!
Comment 23 Dejan Glozic CLA 2007-06-06 15:33:42 EDT
OK, let's wrap this up. Jeff - can we get your vote and call it a day?
Comment 24 Dejan Glozic CLA 2007-06-06 17:46:11 EDT
Released.
Comment 25 Mark Melvin CLA 2007-06-06 19:41:40 EDT
Woohoo!  Thanks for everyone's help.  This is a crucial fix for our upcoming release.
Comment 26 Pascal Rapicault CLA 2007-06-06 21:18:16 EDT
I'm sure that the foundation would be happy to have a screenshot of your app to add to its gallery if it does not already have one.