Eclipse开发RCP应用程序中的一些问题 博客分类: RCP EclipseOSGIjunitUPJVM
程序员文章站
2024-02-21 18:46:58
...
problem
The key can be found in the message: '!MESSAGE Missing required bundle com.dawnatech.misc_0.0.0.' -- note the version number of 0.0.0.
answer
This is due to the fact that your 'misc' plugin is not defined in your quick launch configuration. These are tricky to get right..... I always define a specific quick launch configuration for all of my RCP apps.
I found that merely selecting the 'Launch an Eclipse application' link on the plug-in editor page usually doesn't set up the application and required plug-ins correctly at run time.
This also explains why you think it worked earlier but not later. This has happened to me, as well......
Go to Run | Run... page, create a new run configuration (and name it).
Then, set the Workspace Location to something appropriate for your machine, set the Program to run (product or application).
Then, go to the Plug-ins page and select the 'Choose plug-ins and fragments to launch....'. Deselect all, then select the two plugins in your product/application, and then select 'Add required plugins'.
Every now and again, questions like "Why doesn't eclipse start?" are posted on the newsgroups, or "The application cannot be found". How do you go about debugging these scenarios? This isn't an exhaustive list, but may be a good place to start.
First, some background knowledge. Eclipse uses two writable areas for storing data; a configuration directory (which actually doesn't contain that much other than a config.ini and a few .dlls that have been extracted from bundles) and a workspace , which is usually in ~/workspace on Unix and c:\Documents and Settings\User\workspace on Windows. The workspace has two purposes; to act as a default place for any projects you create, and to have a .metadata directory for storing transient files, as well as anything you've configured in the Eclipse preferences, run-time caches, and a bunch of other stuff.
The config area is usually pretty harmless; if you delete it, it will get re-created on startup. Once created, it isn't usually changed. There's not usually much benefit in deleting the configuration directory, but there's not usually much harm in it either. A default install from unzipping the distribution from Eclipse doesn't have any configuration directory.
When Eclipse starts, it reads two files; eclipse.ini and configuration/config.ini . The former is a list of arguments that get passed to the JVM, whilst the latter is a list of name-value pairs that are set as system properties. If you want to run an Eclipse with an environment value set, you can put it in config.ini as org.example=foo or eclipse.ini as -Dorg.example=foo (after the 'vmargs' flag; if not present, you'll need to add it as an extra arg). Arguments are serparated by newline characters, so you can't put them on the same line. You can also supply these args on the command-line; eclipse -vmargs -Dorg.example=foo .
Eclipse logs all its messages to workspace/.metadata/.log. If you're in Unix, these are usually hidden, but they'll be there. Sometimes, when Eclipse isn't starting, it can help to delete this file first so that you're sure that any problems in starting the environment are not just random messages left over from before.
There's a secondary log, generated when Eclipse doesn't even get as far as starting. For example, if you specify a non-existent VM, then it won't get as far as running any Java code. In these cases, you can often find a configuration/123456.log which contains something useful. If Eclipse isn't starting and not generating a workspace/.metadata/.log file, check the configuration directory for anything suspicious.
The most likely scenario is one where the Eclipse VM starts, but then fails to find out what it's supposed to be doing and shuts down again. What to do then?
Well, clearly, the log may have some answers. Always a good place to look first, rather than guessing. If you do look and don't understand the output, generally posting the entire stacktrace to the newsgroup isn't the best way of finding out. You can generally find out what's going on just by reading the exception messages; and since Java's nested exception handling prints out the full stacktrace of each, you generally just want to scan down for the 'caused by' message at the top of each nested exception. In most cases, the answer is staring you in the face :-)
A good comand to run is:
egrep -A 2 "Caused by:|Exception:" workspace/.metadata/.log
If you're on a primitive OS without 'egrep' installed by default, use Cygwin to install that and other useful tools. Other variants of grep will work as well, but you might have to do two separate greps or miss out on the -A 2 (which prints out the two lines After as well).
It's 'normal' for there to be some errors in the log that are unrelated, so don't take it as read that that's the cause of the problem. Deleting the log before running will give you an idea of what's new, at least.
Some common messages:
NullPointerException ...
Oh joy. Nothing much to say here other than the code needs to be more defensive. Still, it's better than segfaulting, huh?
The bundle could not be resolved. Reason: Missing Constraint ...
Generally, you've got a newer version of a plug-in without its dependencies. For example, you had org.foo.lib-1.0.0 and org.foo.app-1.0.0 , and now that you've installed org.foo.app-1.0.1 it's stopped working. Chances are, org.foo.app-1.0.1 depends on org.foo.lib-1.0.1 or greater, and you've not got that installed. Using a kosher update site like Eclipse Europa discovery site shouldn't have these problems, but always something to be aware of.
java.lang.IllegalStateException: Workbench has not been created yet
This usually comes when someone tries to run a Java application against an OSGi bundle with java -classpath .... . It really means that the workbench plug-in hasn't started yet, and so calls to getWorkbench() fail. This is essentially a race condition, and can be solved by either expressing an explicit dependency on that bundle or bumping up that bundle to a higher start level than the workbench. Generally not seen, but if it is, that's what's happening.
Application "foobar" cannot be found in the registry. The applications available are:...
Either (a) you've mistyped the application ID, or more likely (b) the bundle that contributed the application can't be started. See below.
One or more bundles are not resolved because the following root constraints are not resolved:
Again, a problem with dependencies.
So, now that we know Eclipse is firing up a JVM, but not able to do anything else, where do we go? Well, time to drop into an OSGi console to find out more, or even look at what's going on in the log. Eclipse has a bunch of runtime options , and here are some of the most important ones:
-consoleLog
When starting, dump the messages to the console as well as the .metadata/.log file. Can be quite useful for quickly figuring out what's going on, especially if you don't know where the .metadata/.log file is being written (or assume that it's not being writable)
-noExit
Almost as useful as the last. Basically, even if the application can't be found or there's another problem, don't quit the JVM or OSGi engine. Can make the window hang around rather than disappearing on a Windows system.
-console or -console 1234
Start up an OSGi console interactively, or via a network socket 1234 (to which you can 'telnet localhost 1234' to gain access). Very useful if you're running on a remote machine or don't have access to the console from where Eclipse is being launched. Can do all manner of commands; see below for more.
-data /tmp/newplace or -data c:\temp\newplace
Run Eclipse, but with a workspace that's not the default location. Quite often, if this works but running without doesn't, indicates a problem with the workspace area.
-clean
Used to flush out some (but not all) entries in the workspace metadata area. A good thing to try, and generally safe, but doesn't always have the results intended. If you've not got any preferences, it's sometimes better just deleting the workspace/.metadata directly. If you have got prefs, either export them from the Window -> Preferences beforehand, or save *.prefs from the .metadata/.plugins/org.eclipse.core.runtime/.settings directories. Note that there's a bunch of stuff (like CVS repositories) that probably won't get saved like this; but you did take a backup first, right?
Windows users might also like to know about eclipsec , which isn't a compiler but rather a version of Eclipse that fires up a console window instead of hiding it away. Most of the time, running these with eclipsec is a good way of figuring out what's going on. Unix users can just use the eclipse one. For Mac users, there's a eclipse command you can access through Terminal instead of double-clicking the Eclipse.app .
So, you're through to the OSGi console. When it starts up, it will print out:
osgi>
From here, you can start to figure out what's going wrong. Typing '?' or 'help' will give you a list of available commands; if they scroll off the screen, type 'more' and you'll get paginated output.
Typing 'ss' (for ShortStatus) brings up a list of bundles that are available; they'll be in ACTIVE (running), RESOLVED (ready to run), STARTING (usually indicates a deadlock or stuck thread if you see that for any length of time) or INSTALLED. The last one is the one to look for; it means that the OSGi environment has found the bundle, but one or more of its dependencies haven't been met.
If you find a bundle in the INSTALLED state, you can use 'diag' (for DIAGnostics) to find out what's missing:
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.3.0.v20070530
1 ACTIVE org.eclipse.equinox.common_3.3.0.v20070426
...
123 INSTALLED org.example.foo_1.0.0
...
osgi> diag 123
update@plugins/org.example.foo_1.0.0.jar [123]
Missing imported package org.example.bar_0.0.0.
Missing required bundle org.example.bar.core_0.0.0.
Quite often, if you've got an application that's not starting, it's because 'org.example.foo' defines the application; but the bundle can't start because it's got missing dependencies. The solution is therefore to resolve those dependencies (by installing a missing bundle or a bundle which exports the given package, and you should be away.
You can do this by restarting, or by dynamically adding it in via the console:
osgi> install http://www.eclipsezone.com/files/jsig/bundles/HelloWorld.jar
Bundle id is 456
osgi> start 456
Hello OSGi
You can also stop and start other bundles; once you've brought your dependencies in, you can restart the ones that failed before (e.g. start 123).
Occasionally, if the bundle is RESOLVED (i.e. all dependencies are met) but it still can't start (doing start 123 leads to an exception), then it implies the Bundle Activator's start() method has thrown an exception. That's basically either a programming or configuration error, outside the scope of this post. It's not always an error; for example, a plug-in that connects to a DB might (reasonably) be expected to have the property set via a command line property (e.g. -Ddatabase=foo) otherwise it won't work.
You can find out if there's a setting using 'getprop' in the console:
osgi> getprop osgi.nl
osgi.nl=en_UK
and even set it if it doesn't exist:
osgi> setprop database=foo
osgi> getprop database
database=foo
Of course, you can then do 'start 456' to see if the activator now works.
There's a bunch of other things you can do in the console; for example, if you wanted to see what application extension points were being contributed, you can do:
osgi> pt org.eclipse.core.runtime.applications
osgi> pt org.eclipse.core.runtime.applications
Extension point: org.eclipse.core.runtime.applications [from org.eclipse.equinox.app]
Extension(s):
-------------------
org.eclipse.ant.core.antRunner [from org.eclipse.ant.core]
...
org.eclipse.help.base.helpApplication [from org.eclipse.help.base]
...
You can also find out what extension points are contributed by a bundle:
osgi> ns org.eclipse.help
Extension point(s):
-------------------
org.eclipse.help.contentExtension [from org.eclipse.help]
org.eclipse.help.contentProducer [from org.eclipse.help]
org.eclipse.help.contexts [from org.eclipse.help]
org.eclipse.help.index [from org.eclipse.help]
org.eclipse.help.toc [from org.eclipse.help]
At least doing this will give you confidence that any extension points you've used will be contributed in the list somewhere. If not (or you have something like 'org.example.foo.org.example.foo.FooApp') then at least you can start debugging somewhere.
The last kind of error is more subtle to fix. If you see a message in the log like
The activator org.example.FooActivator for bundle org.example.foo is invalid , then this usually means there has been a ClassNotFoundException trying to load the class in the first place, before it's even got to the start() method.
CNFE is the bane of debugging; the only thing I can say is that it gets easier with practice. A key thing to understand is that if you have a class Foo, and that class references Bar as any kind of method parameter, return type or field type, then in order to load Foo, Bar must also be loaded. This is transitive, so if Bar needs to be loaded, then so does Flubber, and so on. Unfortuantely, when you hit a missing class, the actual class that can't be found is lost in the message and you just get back "Class Foo cannot be found", when clearly it can. Very often, the PDE will give you warnings when you're running into these problems at development time, but sometimes they can make their way past you and into a runtime bundle. Unfortunately, you have to go back to the code to figure it out.
In a bunch of cases, this has been caused by a developer adding a Jar to a Project's Java Build Path and not the OSGi Manifest dependencies. If you have (say) JUnit.jar added onto the build path, then the project will compile, but at run-time your activator will only consult the Bundle-ClassPath to find code. If it can't find JUnit.jar on that path, it will give up and give you the CNFE. The other possibility is that the Bundle-ClassPath either doesn't contain '.' (for classes in the bundle) or it does contain '.,JUnit.jar' but when exporting, the JUnit.jar is missing from the bundle itself. If it's the latter, check the entries in build.properties, and ensure that 'bin.includes=JUnit.jar' is in there. Very often, exporting the bundle and then opening it in WinZip will give you a clue as to what you expected to be in there (but wasn't) and/or consulting what the Bundle-ClassPath is in relation to the contents of the bundle itself.
So, whilst I don't think this will prevent any more questions being posted to the newsgroups in the future, at least it will be somewhere to point people to when they get stuck for reference. If you're experienced at debugging Eclipse startup problems and have any ideas that I've missed, please add comments to the below for the benefit of others. And if you find any glaring errors I've made, please add a comment so I can fix it :-)
I hope you've found this useful. Until next time
The key can be found in the message: '!MESSAGE Missing required bundle com.dawnatech.misc_0.0.0.' -- note the version number of 0.0.0.
answer
This is due to the fact that your 'misc' plugin is not defined in your quick launch configuration. These are tricky to get right..... I always define a specific quick launch configuration for all of my RCP apps.
I found that merely selecting the 'Launch an Eclipse application' link on the plug-in editor page usually doesn't set up the application and required plug-ins correctly at run time.
This also explains why you think it worked earlier but not later. This has happened to me, as well......
Go to Run | Run... page, create a new run configuration (and name it).
Then, set the Workspace Location to something appropriate for your machine, set the Program to run (product or application).
Then, go to the Plug-ins page and select the 'Choose plug-ins and fragments to launch....'. Deselect all, then select the two plugins in your product/application, and then select 'Add required plugins'.
Debugging a failed Eclipse launch
Every now and again, questions like "Why doesn't eclipse start?" are posted on the newsgroups, or "The application cannot be found". How do you go about debugging these scenarios? This isn't an exhaustive list, but may be a good place to start.
First, some background knowledge. Eclipse uses two writable areas for storing data; a configuration directory (which actually doesn't contain that much other than a config.ini and a few .dlls that have been extracted from bundles) and a workspace , which is usually in ~/workspace on Unix and c:\Documents and Settings\User\workspace on Windows. The workspace has two purposes; to act as a default place for any projects you create, and to have a .metadata directory for storing transient files, as well as anything you've configured in the Eclipse preferences, run-time caches, and a bunch of other stuff.
The config area is usually pretty harmless; if you delete it, it will get re-created on startup. Once created, it isn't usually changed. There's not usually much benefit in deleting the configuration directory, but there's not usually much harm in it either. A default install from unzipping the distribution from Eclipse doesn't have any configuration directory.
When Eclipse starts, it reads two files; eclipse.ini and configuration/config.ini . The former is a list of arguments that get passed to the JVM, whilst the latter is a list of name-value pairs that are set as system properties. If you want to run an Eclipse with an environment value set, you can put it in config.ini as org.example=foo or eclipse.ini as -Dorg.example=foo (after the 'vmargs' flag; if not present, you'll need to add it as an extra arg). Arguments are serparated by newline characters, so you can't put them on the same line. You can also supply these args on the command-line; eclipse -vmargs -Dorg.example=foo .
Eclipse logs all its messages to workspace/.metadata/.log. If you're in Unix, these are usually hidden, but they'll be there. Sometimes, when Eclipse isn't starting, it can help to delete this file first so that you're sure that any problems in starting the environment are not just random messages left over from before.
There's a secondary log, generated when Eclipse doesn't even get as far as starting. For example, if you specify a non-existent VM, then it won't get as far as running any Java code. In these cases, you can often find a configuration/123456.log which contains something useful. If Eclipse isn't starting and not generating a workspace/.metadata/.log file, check the configuration directory for anything suspicious.
The most likely scenario is one where the Eclipse VM starts, but then fails to find out what it's supposed to be doing and shuts down again. What to do then?
Well, clearly, the log may have some answers. Always a good place to look first, rather than guessing. If you do look and don't understand the output, generally posting the entire stacktrace to the newsgroup isn't the best way of finding out. You can generally find out what's going on just by reading the exception messages; and since Java's nested exception handling prints out the full stacktrace of each, you generally just want to scan down for the 'caused by' message at the top of each nested exception. In most cases, the answer is staring you in the face :-)
A good comand to run is:
egrep -A 2 "Caused by:|Exception:" workspace/.metadata/.log
If you're on a primitive OS without 'egrep' installed by default, use Cygwin to install that and other useful tools. Other variants of grep will work as well, but you might have to do two separate greps or miss out on the -A 2 (which prints out the two lines After as well).
It's 'normal' for there to be some errors in the log that are unrelated, so don't take it as read that that's the cause of the problem. Deleting the log before running will give you an idea of what's new, at least.
Some common messages:
NullPointerException ...
Oh joy. Nothing much to say here other than the code needs to be more defensive. Still, it's better than segfaulting, huh?
The bundle could not be resolved. Reason: Missing Constraint ...
Generally, you've got a newer version of a plug-in without its dependencies. For example, you had org.foo.lib-1.0.0 and org.foo.app-1.0.0 , and now that you've installed org.foo.app-1.0.1 it's stopped working. Chances are, org.foo.app-1.0.1 depends on org.foo.lib-1.0.1 or greater, and you've not got that installed. Using a kosher update site like Eclipse Europa discovery site shouldn't have these problems, but always something to be aware of.
java.lang.IllegalStateException: Workbench has not been created yet
This usually comes when someone tries to run a Java application against an OSGi bundle with java -classpath .... . It really means that the workbench plug-in hasn't started yet, and so calls to getWorkbench() fail. This is essentially a race condition, and can be solved by either expressing an explicit dependency on that bundle or bumping up that bundle to a higher start level than the workbench. Generally not seen, but if it is, that's what's happening.
Application "foobar" cannot be found in the registry. The applications available are:...
Either (a) you've mistyped the application ID, or more likely (b) the bundle that contributed the application can't be started. See below.
One or more bundles are not resolved because the following root constraints are not resolved:
Again, a problem with dependencies.
So, now that we know Eclipse is firing up a JVM, but not able to do anything else, where do we go? Well, time to drop into an OSGi console to find out more, or even look at what's going on in the log. Eclipse has a bunch of runtime options , and here are some of the most important ones:
-consoleLog
When starting, dump the messages to the console as well as the .metadata/.log file. Can be quite useful for quickly figuring out what's going on, especially if you don't know where the .metadata/.log file is being written (or assume that it's not being writable)
-noExit
Almost as useful as the last. Basically, even if the application can't be found or there's another problem, don't quit the JVM or OSGi engine. Can make the window hang around rather than disappearing on a Windows system.
-console or -console 1234
Start up an OSGi console interactively, or via a network socket 1234 (to which you can 'telnet localhost 1234' to gain access). Very useful if you're running on a remote machine or don't have access to the console from where Eclipse is being launched. Can do all manner of commands; see below for more.
-data /tmp/newplace or -data c:\temp\newplace
Run Eclipse, but with a workspace that's not the default location. Quite often, if this works but running without doesn't, indicates a problem with the workspace area.
-clean
Used to flush out some (but not all) entries in the workspace metadata area. A good thing to try, and generally safe, but doesn't always have the results intended. If you've not got any preferences, it's sometimes better just deleting the workspace/.metadata directly. If you have got prefs, either export them from the Window -> Preferences beforehand, or save *.prefs from the .metadata/.plugins/org.eclipse.core.runtime/.settings directories. Note that there's a bunch of stuff (like CVS repositories) that probably won't get saved like this; but you did take a backup first, right?
Windows users might also like to know about eclipsec , which isn't a compiler but rather a version of Eclipse that fires up a console window instead of hiding it away. Most of the time, running these with eclipsec is a good way of figuring out what's going on. Unix users can just use the eclipse one. For Mac users, there's a eclipse command you can access through Terminal instead of double-clicking the Eclipse.app .
So, you're through to the OSGi console. When it starts up, it will print out:
osgi>
From here, you can start to figure out what's going wrong. Typing '?' or 'help' will give you a list of available commands; if they scroll off the screen, type 'more' and you'll get paginated output.
Typing 'ss' (for ShortStatus) brings up a list of bundles that are available; they'll be in ACTIVE (running), RESOLVED (ready to run), STARTING (usually indicates a deadlock or stuck thread if you see that for any length of time) or INSTALLED. The last one is the one to look for; it means that the OSGi environment has found the bundle, but one or more of its dependencies haven't been met.
If you find a bundle in the INSTALLED state, you can use 'diag' (for DIAGnostics) to find out what's missing:
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.3.0.v20070530
1 ACTIVE org.eclipse.equinox.common_3.3.0.v20070426
...
123 INSTALLED org.example.foo_1.0.0
...
osgi> diag 123
update@plugins/org.example.foo_1.0.0.jar [123]
Missing imported package org.example.bar_0.0.0.
Missing required bundle org.example.bar.core_0.0.0.
Quite often, if you've got an application that's not starting, it's because 'org.example.foo' defines the application; but the bundle can't start because it's got missing dependencies. The solution is therefore to resolve those dependencies (by installing a missing bundle or a bundle which exports the given package, and you should be away.
You can do this by restarting, or by dynamically adding it in via the console:
osgi> install http://www.eclipsezone.com/files/jsig/bundles/HelloWorld.jar
Bundle id is 456
osgi> start 456
Hello OSGi
You can also stop and start other bundles; once you've brought your dependencies in, you can restart the ones that failed before (e.g. start 123).
Occasionally, if the bundle is RESOLVED (i.e. all dependencies are met) but it still can't start (doing start 123 leads to an exception), then it implies the Bundle Activator's start() method has thrown an exception. That's basically either a programming or configuration error, outside the scope of this post. It's not always an error; for example, a plug-in that connects to a DB might (reasonably) be expected to have the property set via a command line property (e.g. -Ddatabase=foo) otherwise it won't work.
You can find out if there's a setting using 'getprop' in the console:
osgi> getprop osgi.nl
osgi.nl=en_UK
and even set it if it doesn't exist:
osgi> setprop database=foo
osgi> getprop database
database=foo
Of course, you can then do 'start 456' to see if the activator now works.
There's a bunch of other things you can do in the console; for example, if you wanted to see what application extension points were being contributed, you can do:
osgi> pt org.eclipse.core.runtime.applications
osgi> pt org.eclipse.core.runtime.applications
Extension point: org.eclipse.core.runtime.applications [from org.eclipse.equinox.app]
Extension(s):
-------------------
org.eclipse.ant.core.antRunner [from org.eclipse.ant.core]
...
org.eclipse.help.base.helpApplication [from org.eclipse.help.base]
...
You can also find out what extension points are contributed by a bundle:
osgi> ns org.eclipse.help
Extension point(s):
-------------------
org.eclipse.help.contentExtension [from org.eclipse.help]
org.eclipse.help.contentProducer [from org.eclipse.help]
org.eclipse.help.contexts [from org.eclipse.help]
org.eclipse.help.index [from org.eclipse.help]
org.eclipse.help.toc [from org.eclipse.help]
At least doing this will give you confidence that any extension points you've used will be contributed in the list somewhere. If not (or you have something like 'org.example.foo.org.example.foo.FooApp') then at least you can start debugging somewhere.
The last kind of error is more subtle to fix. If you see a message in the log like
The activator org.example.FooActivator for bundle org.example.foo is invalid , then this usually means there has been a ClassNotFoundException trying to load the class in the first place, before it's even got to the start() method.
CNFE is the bane of debugging; the only thing I can say is that it gets easier with practice. A key thing to understand is that if you have a class Foo, and that class references Bar as any kind of method parameter, return type or field type, then in order to load Foo, Bar must also be loaded. This is transitive, so if Bar needs to be loaded, then so does Flubber, and so on. Unfortuantely, when you hit a missing class, the actual class that can't be found is lost in the message and you just get back "Class Foo cannot be found", when clearly it can. Very often, the PDE will give you warnings when you're running into these problems at development time, but sometimes they can make their way past you and into a runtime bundle. Unfortunately, you have to go back to the code to figure it out.
In a bunch of cases, this has been caused by a developer adding a Jar to a Project's Java Build Path and not the OSGi Manifest dependencies. If you have (say) JUnit.jar added onto the build path, then the project will compile, but at run-time your activator will only consult the Bundle-ClassPath to find code. If it can't find JUnit.jar on that path, it will give up and give you the CNFE. The other possibility is that the Bundle-ClassPath either doesn't contain '.' (for classes in the bundle) or it does contain '.,JUnit.jar' but when exporting, the JUnit.jar is missing from the bundle itself. If it's the latter, check the entries in build.properties, and ensure that 'bin.includes=JUnit.jar' is in there. Very often, exporting the bundle and then opening it in WinZip will give you a clue as to what you expected to be in there (but wasn't) and/or consulting what the Bundle-ClassPath is in relation to the contents of the bundle itself.
So, whilst I don't think this will prevent any more questions being posted to the newsgroups in the future, at least it will be somewhere to point people to when they get stuck for reference. If you're experienced at debugging Eclipse startup problems and have any ideas that I've missed, please add comments to the below for the benefit of others. And if you find any glaring errors I've made, please add a comment so I can fix it :-)
I hope you've found this useful. Until next time