Archive
CruiseControl.NET and PowerShell–Take 2
I got some good feedback on my last post about building a PowerShell provider for CruiseControl.NET. Basically the question was whether using PS drives was the best approach to use – especially for managing multiple servers. So I have completely refactored the cmdlets to not need the PS drive – and the good news is this has made the coding even easier ![]()
Here are the cmdlets that are current exposed:
Most of these were in the previous version – but there is one major change – New-CCConnection has replaced Get-CCServer. I’ll come back to why for this later on.
So with the changes the commands now look like this:
To work with projects we now directly use Get-CCProject rather than using Get-ChildItem. This has been simplified to take in either the server name or connection and directly return the projects. This can also be filtered by putting in a name parameter.
In the screenshot above I’m directly working against the name of the server (in this case localhost.) To allow this I’ve made some changes to the name resolution. If connecting to localhost or 127.0.0.1 it will use .NET Remoting (TCP connections) – all other names will default to HTTP. It is still possible to connect via .NET Remoting – just have to put in the full URI for the server (including the protocol.)
I’ve also expanded the connections out so it is possible to use a backwards compatible connection (for connecting to pre-1.5 version servers) and allow encrypted connections. These can be turned on by adding the relevant flag to the command (note – they are mutually exclusive – if both are used an error will be thrown!)
Now to simplify connecting to a server I have added a cmdlet called New-CCConnection. This will take in the parameters for a connection and return a connection instance (if the connection is valid.) This connection can then be used in any of the commands. Now, while this may seam to add overhead (beyond reducing the number of keystrokes per command) the beauty of the command comes when we want to use security. For example if we have a secured server:
In this screenshot I started two connections – the first time it was an unsecured connection, the second it was secured. Both connections can view the projects (this is the way security has been configured) but only the second connection can force a build.
And for a final fun example, here is a screen shot showing how it is possible to work with multiple servers at once:
I don’t actually have two servers running – hence all the projects are duplicated – but it shows how we can set up two different connections and pipe them into the Get-CCProject cmdlet to retrieve all the projects. Note there are no queues for the connection that uses backwards compatibility as this feature was added in v1.5.
So hopefully this is more useful now. For my next post I’ll try and add some new functionality to make the cmdlets more useful ![]()
CruiseControl.NET and PowerShell
It’s been a while – I’m still busy with work, study and a family – not as much time to write as I would like ![]()
I’m currently playing around with PowerShell in my job at the moment. Basically we never have enough time, so I’m trying to figure out how to automate various tasks via PowerShell. And I’ll admit, so far I like it! It is easy to use, has a lot of power and flexibility and there are limitless possibilities for what can be done. But this post isn’t about PowerShell in general – instead I’ve been playing around with building a PowerShell provider for CruiseControl.NET.
“What? But why?” you might say. A while back I built a command-line tool that allows people to interact with a CruiseControl.NET server. But it is very limited and is fairly complex for what it actually does (in terms of the code for it.) As I was playing around with PowerShell I started thinking a lot of the syntax in PowerShell would allow me to build a much better command-line tool, especially when I started seeing the extensibility options for PowerShell.
So I have started putting together a PowerShell provider for CruiseControl.NET. This allows an administrator to connect to a CruiseControl.NET server and administer it. As I’m still playing around with things the code is production quality yet, so use it at your own peril! There is no installer – you will need to grab the code off SourceForge and build it, then copy the contains of the PowerShell\Bin\Debug folder into your modules directory (see help about_modules in PowerShell.)
However if you are interested in seeing what can be done, take a look at the following screen shots:
Here I am:
- Importing the module
- Seeing the new drive that has been mapped
- Getting the child items in the various folders
- Starting all the projects
- And forcing a build for all the projects
I like how I can work with multiple projects at the same time – in my previous tool we would have needed to run the tool once for each project!
I have implemented the cmdlets in the provider to use the pipeline, so we can use a lot of the functionality within PowerShell. For example if we only wanted to get the projects for a certain queue:
This is something that wasn’t even thought of in the command-line tool! And here it is, without any extra work on my behalf ![]()
At the moment I have only implemented four cmdlets:
- Get-Log
- Start-Project
- Stop-Project
- Start-Build
Plus the provider infrastructure (i.e. you can use built-in cmdlets like Get-Item, Get-ChildItem, Set-Location, New-PSDrive, etc.) Currently I have mapped the local server to local:. It is possible to connect to other server using New-PSDrive as long as you know the address for it (this is the same address that CCTray uses.) I have implemented the provider as a hierarchy. The top level is the server itself, with two sub-folders: Queues and Projects.
My next step is to add builds in, but I think this is going to need some changes on the server side to work.
Hopefully this will be helpful to someone ![]()
CruiseControl.NET – vNext – Trialling the New Communications Infrastructure
Work on vNext has unfortunately slowed right down at the moment (mainly due to university having started again) but I have managed to spend a little bit of time playing around with the communications side. In the current versions of CruiseControl.NET it is a pain to add a new method to the client API – there is around half a dozen classes that need to be modified just to modify the API plus the actual implementation details (and getting to the implementation.)
In vNext I want to make adding a new method as simple as setting an attribute on a method
I’ve already talked a bit about the design in my posts on Universal Naming, Three External Methods and Invokable Methods, with this in place I was ready to test whether it would work or not.
To do this I put together a simple command-line application to work as an interactive “console”. This has a few simple commands that the user selects for performing the various operations. It’s not much to look at but it does allow some simple testing:
The main commands are:
- query (? for short): this lists the available commands for the current URN
- invoke command (.command for short): invokes the command on the remote server
- up name (+name for short): adds the name to the current URN
- down (- for short): removes the last part of the current URN
- quit: exits the console
This provides the basics for querying, invoking and navigating the remote server. In the above screenshot I’ve shown an example of how this works.
Note: this console has a large number of limitations at the moment – it is only a proof of concept for testing!!
In the above screenshot there are only two commands available on a project – Start() and Stop() – not enough to do much with a project. It would be nice to add a command to retrieve the current status. So I opened the code for Project and added the following method:
public virtual Messages.SingleValue GetStatus(Messages.Blank request)
{
var response = new Messages.SingleValue(this.State.ToString());
return response;
}
The method is very simple – all it does is return the current state as a string. In order to expose a method in the API a method needs to have a single input argument and a return value. In the Common library I’ve added some basic messages in the Messages namespace to simplify this process.
Note: at the moment the console only handles messages that take in a blank message – I did warn you there are severe limitations ![]()
The next step is to expose this as an action in the API. This is as simple as adding a RemoteAction attribute:
[RemoteAction]
[Description("Retrieves the current status of the project.")]
public virtual Messages.SingleValue GetStatus(Messages.Blank request)
{
var response = new Messages.SingleValue(this.State.ToString());
return response;
}
I also added a description attribute to provide some help on action.
Note: yet another limitation in the console – no way to see this help yet – the server is actually returning the information
Now I can query the server and see the new method. When I call the method it will return the current state:
Nice and simple to add a new command to the API
Of course, there is a lot more work to do on the client side but at least the workload has been reduced on the server development!
Now, the next question is what if we want a different result set than one of the standard messages? Again this is easy enough to implement. First add a new class for the return response:
public class ProjectStatus
{
public string Status { get; set; }
public DateTime LastBuildDate { get; set; }
}
And then use the class in the method:
[RemoteAction]
[Description("Retrieves the current status of the project.")]
public virtual Messages.ProjectStatus GetStatus(Messages.Blank request)
{
var response = new Messages.ProjectStatus
{
Status = this.State.ToString(),
LastBuildDate = this.PersistedState.LastIntegration.FinishTime
};
return response;
}
Now when we call the command we get the custom message returned instead:
So still nice and easy ![]()
For those who want to know the technical details:
- The messages are encoded as XAML, hence why the cyan text in the screen shots is XML. XAML handles the serialisation and deserialisation nicely without any extra work on our part.
- The querying and invoking is done via reflection. The ActionInvoker class in the code is responsible for this.
- The communication is all via WCF at the moment – and there are two possible channels (HTTP basic and NET.TCP). However both are extendable and over time these will be expanded.
- There is a simple class in the Common library called ServerConnection which implements the low-level client functionality. In time I hope to build some higher level APIs to make it really easy to use.
Security in CruiseControl.NET
From CruiseControl.NET 1.5 onwards there is the option to configure security. Unfortunately due to some limitations in the way it was implemented it is only always easy to figure out how to do it. Recently there was a question about why are the projects not visible in the dashboard after security was added. In this post I’ll go over why the problem occurred and some possible ways to fix the problem.
Here is an example configuration that demonstrates the problem:
<cruisecontrol xmlns="http://thoughtworks.org/ccnet/1/6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<internalSecurity>
<users>
<passwordUser name="Bob">
<display>Bob the Builder</display>
<password>Bob1</password>
</passwordUser>
</users>
<permissions>
<rolePermission name="Builders">
<forceBuild>Allow</forceBuild>
<defaultRight>Deny</defaultRight>
<users>
<userName>
<name>Bob</name>
</userName>
</users>
</rolePermission>
</permissions>
</internalSecurity>
<project name="SecurityTest">
<security xsi:type="defaultProjectSecurity">
<defaultRight>Deny</defaultRight>
<permissions>
<rolePermission name="Builders" ref="Builders" />
</permissions>
</security>
</project>
</cruisecontrol>
Here there is an user called bob the Builder who has forceBuild permission – all other rights are denied. The problem is there is another right called viewProject which controls the visibility of projects in the dashboard. Since all other permissions are denied this permission also is denied, so the project does not appear in the dashboard!
Now if we are happy only allowing Bob the Builder to see project then the solution is easy – add a viewProject right and set it to Allow:
<rolePermission name="Builders">
<forceBuild>Allow</forceBuild>
<viewProject>Allow</viewProject>
<defaultRight>Deny</defaultRight>
<users>
<userName>
<name>Bob</name>
</userName>
</users>
</rolePermission>
Now when Bob the Builder is logged on he can see the project. But what if we want to allow everyone to see projects?
To allow this we need to add a guest account with the view permission as well:
<cruisecontrol xmlns="http://thoughtworks.org/ccnet/1/6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<internalSecurity>
<users>
<passwordUser name="Bob">
<display>Bob the Builder</display>
<password>Bob1</password>
</passwordUser>
<simpleUser name="Guest" />
</users>
<permissions>
<rolePermission name="Builders">
<forceBuild>Allow</forceBuild>
<viewProject>Allow</viewProject>
<defaultRight>Deny</defaultRight>
<users>
<userName>
<name>Bob</name>
</userName>
</users>
</rolePermission>
</permissions>
</internalSecurity>
<project name="SecurityTest">
<tasks>
<commentTask>
<message>Ran successfully!</message>
</commentTask>
</tasks>
<security xsi:type="defaultProjectSecurity">
<defaultRight>Deny</defaultRight>
<guest>Guest</guest>
<permissions>
<userPermission user="Guest">
<defaultRight>Deny</defaultRight>
<viewProject>Allow</viewProject>
</userPermission>
<rolePermission name="Builders" ref="Builders" />
</permissions>
</security>
</project>
</cruisecontrol>
This example adds a new account called Guest, sets it as the guest account for the project and gives the account view permission. Now everyone can see the project in the dashboard.
Note: the Builders role still needs the viewProject right – otherwise when Bob logs in he will no longer be able to see the project!!
Visual Studio Code Metrics in CruiseControl.NET
http://blog.kynetix.com/2011/01/31/computing-visual-studio-code-metrics-during-builds/
posted about how Microsoft has released a command-line version for generating static code metrics. The only thing they mentioned was lacking is integration into CruiseControl.NET. Since this was nice and simple I put together a quick version and wrapped it in a package:
If I get time I’ll try and add some jQuery smarts to it sometime, but it does show the basics. Feel free to improve it ![]()
CruiseControl.NET – vNext – Controlling the Flow
Over the past day or two there have been a couple of interesting scenarios raised about the “flow” within CruiseControl.NET. At the moment I don’t have an answer for these issues so this post is more about raising the visibility so they don’t get forgotten.
The first issue is about interrupting tasks. While we are making some changes to tasks to allow for breaking the flow of a task these changes are more for tasks that are containers of other tasks. However another scenario was raised recently where we might want to break the internal flow of a task. By this I mean we want to stop a task from running during its normal process. This was raised in response to the parallel task – where there are two tasks that take a long time. If one task fails then there is no point in continuing the other task – instead it should be cancelled so the entire build is failed more quickly.
This however raises the issue of forced vs. co-operative cancellation. The preferred approach is co-operative cancellation. Both the task and its parent share some mechanism for cancellation. When the parent cancels the task it stops at the first convenient opportunity. This means it can ensure that everything is reset to a proper tidy state and there is no corruption of any data. The other approach – forced cancellation – is where the parent just kills the task. This means the cancellation is immediate – no need to wait around – but it also means that data can be corrupted. In other words we have absolutely no idea of what has happened!
Now we could expand the mechanism that is already in place for vNext to handle returning non-tasks (perhaps null) and then let the parent container handle the cancellation. But the current mechanism is specifically for running tasks so it would mean making the process more complex and it still wouldn’t allow for the task to perform any tidying up. An alternate is to add a new mechanism for cancelling the task and then getting the task itself to monitor this mechanism (similar to how cancellation works in .NET 4.0.)
Something to think about – I’m open for any suggestions on what people think will be the best way.
The second issue is around additional control for the meta-structures (queues, gates, etc.) Currently there are four meta-structures we are planning on adding:
- Queues: Allow only one (or more) active integrations at a time – take the next integration either LIFO or FIFO
- Round-robin: As a queue but using round-robin scheduling
- Gate: Waits for all active integrations to complete before allowing the next item to continue – this has a variation that will trigger all the children when the gate is hit
- Pipeline: Only allow the children to trigger within the order they are within the pipeline – one variation will wait for external triggers, the other will trigger each item in sequence
The additional control that was requested is for a “clean-up” integration to start when a queue has finished (i.e. there are no active integrations.) There are two ways I can think of doing this at the moment. One is we add a new control structure (e.g. GatedQueue) that remains active until the queue is clear. This could then be combined with a pipeline to trigger the “clean-up” integration. The second is we add start-up/clean-up properties to the queue that contains projects that must be run before/after the queue. At the moment I prefer the first approach as it is a bit tidier.
Does anyone else have any suggestions or preferences?
UI Goals: Patrick
Continuing with the UI design we come to Patrick’s goals. As I stated in the personas (read them here) I’m not really sure that Patrick is a primary persona but as he is probably going to need a separate interface for his work I’m treat him as a primary persona with a complete set of goals.
Simple and easy to use
Since working with CruiseControl.NET is only a small part of Patrick’s job he does not want to have to spend a lot of time learning the system. The interface should be intuitive to use, allow him fix any mistakes without them becoming serious problems and only require a minimum of work. He should also be able to setup “templates” for different projects that can be quickly applied.
Configure the entire system
Patrick should be able to configure everything in the system from a single console. He should not need to swap between different programs to set things up. This includes setting up, configuring and upgrading multiple different build servers. The “everything” that he needs to configure includes the different build projects, users and their security access, servers, etc.
View complete diagnostic information on the entire system
When Patrick is trouble shooting he should be able to see exactly what has happened if anything fails. When an integration fails he needs to know which project failed, which step in the integration and why it failed. Since he is only called in for fixing the problems that developers can’t (since he growls at them if they bug him) he needs to see more than just want the developers see. This information includes details about the servers (memory, CPU usage, available disk space), any other processes that were running (and might have caused interference), etc. Of course the information should be in a format that makes it easy for him to spot the cause of the problem quickly!
Automated monitoring
Given that Patrick prefers not to be bothered by developers he would much rather be notified of problems by the system directly rather than the developers. This means he can fix things before they come to him, which in turn makes the developers even more impressed with his abilities. As such he wants the system to notify him when certain parameters are exceeded. As he already monitors other systems and servers for Rainbow Interactions he wants the notifications for CruiseControl.NET to appear in his monitoring tool rather than needing a separate tool.
Comparing Patrick’s goals with Michelle’s we see that they both have a different focus. Patrick prefers an in-and-out approach – get in, do his tasks and get out – as quickly as possible. He also does not want to become an expert in the system so it needs to be as easy to use as possible. In contrast Michelle is more of a regular user. She is happy to spend some time to become familiar with the system if it will make things easier for her in the long run. They also both have some common features: it should work within their current tools, it should notify them when things go wrong and it should provide them access to everything they need in a single location (although for Michelle this will be two different locations.)
Hopefully this is starting to sound like an interesting challenge ![]()
Next step, time to put together some context scenarios to provide some generic detail on when and how they will approach their different tasks. Stay tuned…
UI Goals: Michelle
In my last post I described a couple of personas for designing the UI/UX for a new CruiseControl.NET (read it here.) In this post I’ll take these personas and outline some goals for them.
For both of the personas we need an experience goal (what sort of experience they expect to have when using the system) and some end goals (what they are trying to achieve.) These are not technical goals instead they need to be aimed them at a higher level – what is the user trying to achieve. This gives us some more flexibility around how we meet the goals (i.e. the goal does not describe how it can be achieved.) In this post I will cover the goals for Michelle:
Flows with her working style
Michelle has two primary ways to access the build information: from within Visual Studio and over the web. She should be able to see the same information and make the same changes from both Visual Studio and the web. All build information and artefacts need to be accessible.
Displays all the information to diagnose problems with a build
When a build goes wrong Michelle needs to be able to quickly and easily see where things went wrong and why. To start with she needs to see that there is something wrong with a build. From here she should be able to drill down to find the exact place that the build failed and why. She would also like to see who added the code that failed the build and when.
Control a build project
As the lead developer for Here and Now Shipping’s system Michelle needs to have full control over how the build project works. The main action she needs to do is to start a new build integration, but she also needs to occasionally abort builds, start and stop the process, etc. A task she performs on a much lesser basis is modifying the configuration for a build.
Be notified when something goes wrong
If something goes wrong Michelle needs to be notified as soon as possible. She does not want to have to wait until she manually checks to find out something is wrong. The notification needs to have sufficient detail for her to know where to start looking for the problem.
As you can see these are all very high-level. They describe what the user (in this case Michelle) wants to do in the system without providing the implementation details. The next step in the process is to put together some scenarios that show when Michelle would use the system.
So stay tuned, more information is coming…
UI Personas
An important part of designing an user interface (UI) or user experience (UX) is to know who we are designing for. One of the tools for this in interaction design is to develop some personas. These are fictional people who embody all the goals of actual users of the system. So for re-designing the UI for CruiseControl.NET I have put some personas together.
Note: these are not true personas as they are not based on research. Instead they are based on my understanding of a typical user; so they will not be as effective as true personas.
Patrick
37 year old male
Patrick is the systems administrator in a team of 12 at a small software development house called Rainbow Interactions. His job involves implementing and improving processes within the team. He directly reports to the CEO of Rainbow Interactions and often works directly with their customers. As such he has a very busy schedule and likes his time to be as streamlined as possible.
Outside of work Patrick is married with three children. As he spends a lot of time at work during the week he refuses to work during the week-ends so he can spend time with his children. He enjoys walking in the wilderness and so will often go away during the week-ends; which also means that work cannot contact him with any “emergencies”.
Patrick is involved in the initial setup of every project and then helps the other developers as required. He is also involved in cleaning up after each project has completed. His work varies from day to day depending on where in the project cycle the team is at. At the beginning of the project he makes time for setting up everything required for the project, including continuous integration (CI). During the project he will help the developers trouble shoot problems and even occasionally write code. Finally at the end of the project he archives all the work for the client. He might also go to the client’s site to help transfer the work over if necessary.
As part of their process for working on client projects they always set up a new CI process. Each process has a common core with the basic functionality (e.g. retrieve latest changes, compile the code, etc.) but they can all be customised depending on the clients’ needs. While Patrick sees this as an important part of his job he doesn’t have much time that he can spend on setting up CI processes. Instead he just comes in, copies the default template and then adds in the modifications as required. As different developers can be working on different projects, and sometimes the clients also have access, he likes to lock down the processes so only the relevant people can have access.
Patrick only helps with trouble shooting if there is a problem that the developers cannot solve themselves. His first question when they come to him for help is to ask what they have already done. If they have not tried anything (e.g. don’t know where to start) or they have missed something then he will advise them where to look. If it is a problem outside of their ability or capacities then he will get involved. These are normally problems on the CI servers (maybe bad configuration, maybe server issues, etc.) The first place he always looks is the server logs and from here he will trace the problem. As such he likes to see as much information as possible (which might include elevating the logging level to get additional information.)
To archive a project all he does is select the project and the destination and then starts the process. This copies everything to the destination and removes the process from the server. Later on he can restore the process or he can install it on another CI server if needed.
Michelle
26 year old female
Michelle is a developer at Rainbow Interactions. She has been working on a project for their most important client – Here and How Shipping – for the past five years and has recently become the lead developer for their system. Since Here and Now Shipping has been with Rainbow Interactions for several years now they have a well-defined CI process. However from time to time things change and the process needs some improvements (for example they learnt about code coverage recently and wanted that included.)
Michelle’s day-to-day job is very simple – she takes the list of requirements she gets given from the business analyst at Here and Now Shipping and works with her time to implement them as quickly as possible. Most days this involves writing code, sometimes testing, sometimes bug fixing. No matter what she is doing though she is always running short of time and will often stay late at work, with the occasional week-end day as well.
She just expects the CI process to work – when she (or any of the other developers) checks in code for Here and Now Shipping’s system it should automatically build and then notify her of any problems. If the build goes fine she doesn’t care (although sometimes she might look at it to just touch base” but it breaks she wants to know as soon as possible. When the build does break she wants as much information on why it has broken as possible so she can either fix things or chase down the person who broke it. The last thing she wants to do is bother Patrick as he is often grumpy if developers bother him without a “good” reason.
Her primary development environment is Visual Studio, but she also accesses build information remotely via the internet. She likes to see all the information possible on the build (number of changes, which unit tests were run and how long it took, the amount of coverage, any coding rule exceptions, etc.) She also needs to start and stop the process, trigger builds and modify the configuration if necessary. Basically she needs to do everything with the CI process for Here and Now Shipping. But conversely she doesn’t care about any of the other clients Rainbow Interactions works with.
Of these two personas I’d put Michelle as the primary persona as she is the main user of the system. However Patrick would have a different set of interaction goals so he would probably be another primary, although not as important as Michelle.
In my next post I’ll look at some interaction goals these two personas have and maybe some scenarios. With these in place we can start to look at how we can design the interaction process for our users. ![]()
Stay tuned…
The UI of CruiseControl.NET: Introduction
I’m going to take a break from looking at the inner workings of CruiseControl.NET vNext for a while. Instead I’m going to spend some time posting about another important area that doesn’t get as much attention – the User Interface (UI).
There are some areas in CruiseControl.NET (CC.Net) that tend to turn people off. I often see people mentioning they use alternate products because of “blah”. Now these are not necessarily UI problems but a good UI can go a long way to helping people enjoy a product despite other problems (just look at Apple products as a prime example!) So any love and attention we put into the UI will pay off a 100-fold.
The following diagram shows the current components and their interactions in CC.NET:
The server is a black box to the user. Yes there is a console version that will display the log but the user has no way of interacting within the server beyond just seeing what is happening.
Instead the user needs to use an external component to interact with the server. For example the web dashboard is a web-based application that allows a user to see what is happening on the server and to make some limited changes (e.g. force/abort a build, etc.) The grey lines show the direct communications with the server – which is via .NET Remoting.
CCTray is the second type of interface application. It is a Windows-based client that also allows viewing the server status plus some changes. Unlike the dashboard it can use HTTP-based communications but this is an indirect path – it needs to go via a dashboard to actually connect to a server. And CCTray tends to be a lot more limited in the functionality it offers.
There is a third path of interaction – via the ccnet.config. This is the path that the validator takes. It does not directly interact with the server at all, instead it reads the same configuration. And of course people directly modify ccnet.config as the ultimate way of controlling the server.
There are also a few more applications that can be used to interact with the server: cradiator (BVC), FastForward.NET, CCCmd, etc. These all tend to fit in the same space as CCTray in that they use either HTTP or .NET remoting to connect to the server (although some only use HTTP.)
Each of the various UI components has their own limitations. The dashboard is reasonably easy to configure and extend (if you know how it fits together) but it is global in scope. There is no way to configure it to have custom views for each user. In contrast CCTray is easy to personalise but the options for extending it are very limited (especially as there is no plug-in framework for it.) Plus going via the dashboard for HTTP means it can be slow. Finally (and this is one of the main complaints I see) there is no way to easily modify the configuration. The config file is XML – if you want to configure CC.Net you have to use XML. End of story!
So going forward I’m going to look at how we can apply some interaction design principals to CC.Net to improve the user experience. If there is anything that annoys you about the current UI or any suggestions you have let me know and I will see if (and how) they can be resolved or added.