Profil von Bob NovasBob Novas's WebLogFotosBlogListenMehr ![]() | Hilfe |
|
16 März Crusty Rustic BreadWell, here it is. My recipe for some really good bread. It’s not actually my recipe – it’s straight out of the King Arthur Flour Baker’s Companion – the recipe for Baguettes on p. 239. My contribution is how to actually cook the stuff. What I’ve found is that making bread is incredibly dependent on the process. Use one process, and you get cake-like white bread – ok, I suppose, but not very inspiring. Put the same dough through a different process, and you get crusty, rough textured peasant bread. That’s the process I want to describe. This is a two day process – it doesn’t take you all that long to do, it just takes a while for the bread. All my measurements are by weight. I use a scale, put the bowl on the scale, zero the scale, and put the ingredient in. To start with, sometime in the morning the day before you want to eat the bread, make the poolish. Put 5¼ ounces (by weight) water in a largish bowl. I use bottled water, assuming that it has less stuff that kills yeast in it. Thoroughly mix in a pinch (1/8 teaspoon) of active dry yeast. Now add 5¼ ounces (by weight) of King Arthur bread flour (not all purpose flour, you want the really glutinous stuff), and mix it in with a wisk just enough so the flour and water and yeast are all mixed. Now cover this with plastic wrap, putting the plastic wrap right on top of the poolish, and let this sit all day. Sometime before you go to bed, the poolish should have risen and become bubbly sticky goo. Now, take your mixer bowl (empty), put it on your scale and add 5¼ ounces of water (bottled). Again thoroughly mix in 1½ teaspoons of active dry yeast. (I just toss in a little less than the rest of the packet.) Add 10½ ounces bread flour, the poolish and 2 teaspoons of salt. Mix this with a dough hook for less than a minute, until all the flour is all wet and then let it sit for a while. You can let it go for 20 minutes. Now actually knead the dough for a couple of minutes. The result should be very wet dough that’s just starting to ball up. Lightly oil (olive oil) a bowl, put the dough in the bowl, and cover it with plastic wrap, again putting the plastic wrap right on the dough. Now put this in the fridge and leave it over night. In the morning take the bowl with the dough in it out of the fridge – it should have risen some. You can fold the dough over a few times and put it back in the bowl, covered with plastic wrap. Let it go a couple of hours and fold it down again. At least 2 hours before you're going to bake the bread, divide the dough into two pieces and roll it into two sticks about 18” to 20” long on a floured surface. Put the sticks into a baker’s couche (burlap) in a concave form and let the bread rise as long as you can stand it – for a couple hours at least. This next part of the process is the magic that makes the bread crusty and chewy and coarse grained. An hour before you’re going to bake the bread, turn your oven on as hot as it will go – 500 degrees F at a minimum. Put a baker’s bread stone on the middle shelf of the oven and a large shallow iron skillet on the bottom shelf and let these things get good and hot. 15 minutes before you’re going to bake, get some water boiling. Roll the sticks one stick at a time from the couche onto a floured flat aluminum tray, score the top of the bread with a lame if you want to, and slide each stick one at a time onto the bread stone in the oven. The sticks will be flatish and wide – since they’ll sink when you take them out of the form. Pour a cup of the boiling water into the shallow skillet to make steam (watch out!) and use a spray bottle to spray water on the bread and stone. Get a good bit of steam going in the oven and shut the door. Set a timer for 15 minutes. Let the bread bake for a couple of minutes and reduce the oven temperature setting to 475. Then let the bread bake for the remainder of the 15 minutes. The bread should quickly “spring” from the flat shape it started from, and form some good sized baguettes. I believe that what gives the bread it's chewy texture and coarse grain is that you bake the bread directly on the bread stone, putting the whole bottom of the bread on the blazing hot surface of the stone. If you bake the bread in a baguette form, that concave metal thing, the bread bakes slowly since the form is cold when you put it in the oven. But if you slide the bread right onto the hot stone, the whole bottom of the bread is rapidly heated, and it's this that causes the bread to rise in a rapid fashion, creating the delicious texture. 09 März Thoughts on Microsoft Office 2007 Groove EventsSince writing “Using Web Services Helpers to Access Events in Groove 2007”, I noticed a puzzling behavior that I finally understood that I wanted to mention. Also, there have been some upgrades to the Web Service Helpers event mechanism that are noteworthy that I wanted to blog about. Subscribing to Events from more than one Event Source over a Long DurationExample 3, Aggregated Tool Event Handler, illustrates adding an Aggregated Tool Event Listener for two event classes – Forms and Forms2. There’s no problem with that. The code as shown creates new subscriptions to Forms Events and Forms2 Events whenever the Forms app starts. But suppose you’ve written an application that you want to subscribe to events for an indefinitely long time. Presumably, over that time, the computer will be shut down and re-started. You want your application to receive all Groove events that occur on several event classes, without missing any, even if the user re-starts the computer. The Helpers provides a way to subscribe to an existing aggregated event subscription that you would use to do this. The problem is that using this technique naively can lead to undesirable behavior. You would think that you simply call AddAggregatedToolEventListener() using the overload that has an event subscription ID parameter. This would inform the EventManager that you want to use an existing subscription. The problem arises if you make more than one such call to AddAggregatedToolEventListener(), to listen for events from more than one Event Class – like Forms2 events and Files events. The first call to AddAggregatedToolEventListener() starts the EventManager.EventManagerThreadProc() running and reading events from an event queue internal to Groove. It also sets up an EventManager expecting events from the given subscription. The next call to AddAggregatedToolEventListener() would set up an EventManager expecting events from a different subscription. But, at the point when the first call to AddAggregatedToolEventListener() is made, the EventManager for the second subscription isn’t set up yet. So, if there happen to be any events queued for the second subscription, they will be delivered to the EventManagerThreadProc, which will not only discard them, it will add their SubscriptionID to a list of SubscriptionID’s to ignore, from that point forward. This will be reported to System.Diagnostics.Debug, but probably won’t be a happy circumstance for your program. The solution is easy. EventManager has a public static EventsEnabled property. You should set the EventManager.EventsEnabled property false before the first call to AddAggregatedToolEventListener(), and set EventManager.EventsEnabled true after the second (e.g., last) call to AddAggregatedToolEventListener(). That prevents the EventManagerThreadProc from running and discarding any events for subscriptions that haven’t been set up yet. EventManager.EventsEnabled should be used in this fashion whenever subscribing to events from more than one event class. Maintaining an Event Subscription that Survives a Groove RestartThe next thing I wanted to mention was how to write an application that consumes Groove Web Services and works even if the user stops Groove and then restarts it, without re-starting the application. This is the case, for example, if the application is written as a Windows Service or a Startup application. Such an application’s lifetime is independent of the lifetime of the Groove client whose web services the application consumes. The latest versions of the Groove Web Services V12 Helpers (Release 9 and later) have been modified to address this issue. These versions of the Helpers ensure that web service operations are made with the current Groove Web Services Request Key – this was a problem in earlier versions because the Helpers cached the Web Service headers and hence the Request Key. The Request Key changes whenever Groove re-starts. So unless your application re-starts in synchronicity with Groove, the Helpers used the wrong Request Key and web service operations failed. The newer versions recreate the headers if the Request Key changes. The Helpers also update any subscriptions using the correct header. The one thing that the Helpers can’t address is if the Groove client is shutdown so long that the Event Subscription actually expires (Event Subscriptions are created with a declared time-to-live). This is unlikely, but it is possible. In this circumstance, the Helpers EventManager delivers: IGrooveWebServicesAdvancedEventCallback.OnSubscriptionUpdated (GrooveWebServicesV12Helpers.Subscription)
Where the subscription has a non-null ErrorMsg property. This is the only case when the ErrorMsg property is not null. The message reports “Could not find element with ID={0} within the document”
If your code handles OnSubscriptionUpdated() and receives this message, the proper thing to do is to create a new Subscription – the old Subscription has expired and won’t be productive. 06 März Exchanging InfoPath Forms between SharePoint and GrooveThis blog is about exporting an InfoPath form from a Microsoft Office 2007 Groove InfoPath Forms Tool and importing the form to a SharePoint Forms Library. Why would you do this? This might be useful for people who collect information in Groove Forms Tool records while roaming the field disconnected from any network, and who then connect to a network at night – the information collected on the Form records could be aggregated to a central SharePoint Form Library. Alternately, say you have intermittently connected employees that you want to task using dispatch forms – you could have a central SharePoint site where you submit dispatch forms and the forms trickle out to the field employees who receive them on laptops connected to the Internet via air cards that have only spotty connectivity. A Groove InfoPath Forms tool in a Groove workspace would serve to get the dispatch forms to the employees with no fuss or muss – no VPNs, no logins, just secure forms synchronization from the central site to the laptops running Groove when there is connectivity. Figure 1 illustrates a system schematically.
Figure 1 - System Overview So here’s the starting point – you have a SharePoint site and an un-designed Groove InfoPath Forms tool and you want to set things up so you can exchange forms from one to the other. Basically you’re going to design a form in InfoPath 2007, and then import this form design (a “template” or .xsn file) into Groove and SharePoint. Then you’re going to create a form in Groove, export the form to a file and import that file into SharePoint, or create a form in SharePoint, export that form to a file and import that file into Groove. To begin with, you use Office 2007 InfoPath to design a form and save the form design as an InfoPath Forms template (an .xsn file). There are some restrictions on the design of this form in order to be able to use the form in a Groove InfoPath Forms tool. These are listed in the “Microsoft Office Groove Help” available from the Groove Help menu, under the topic “About Groove InfoPath Forms Tool”. You may want to design the form specifically for Groove, import the template to Groove and then change some of the restricted settings for SharePoint. No matter what, there’s clearly an issue here – you either wind up with two templates that you have to manually keep in sync or you keep just one template (the Groove one) that when you update, you save a copy for use in Groove and then make the same changes for SharePoint. You’ll have to think this through for your own situation. So, let’s say you’ve got a form template suitable for use in Groove. You import this .xsn file into a Groove InfoPath Forms Tool and create a Groove form with the same design. You make some changes to the settings of the form template (but not to the design) to make it more suitable for SharePoint (e.g., where to submit the form) and you create a SharePoint forms library using this template. You can now use this form to create records in Groove that represent the filled in values of the form. So the question now is – how to export the xml from the Groove InfoPath Forms tool to files that you can get into the SharePoint Forms Library (or vice-versa). I’d like to show how to do this using the Groove Web Services Helpers, available from CodePlex (http://www.codeplex.com/GWSV12Helpers, Release 9 or later). Furthermore, I’m going to use the Groove Web Service Helpers Command Line Utilities, available from the same URL. You’d probably never use the command line utilities for an operational system, but using the command line utilities is a great way to demonstrate step by step how to perform the process. Since the full source code is provided for the utilities, it’s then entirely possible (and up to you!) to program a solution to do the same thing automatically. Suppose you have the Helpers command line utilities working; you have a Groove workspace with an InfoPath Forms tool; and, there are some forms entered in the tool. Here’s how to go about exporting the forms from the tool. First you’ll need to get some URI’s to the various pieces. You’re going to need the URI of the workspace, the tool, the form, and the record(s) you want to export. It doesn’t matter which Groove system you get this information from – in a Groove workspace with multiple endpoints, these URIs are the same at every endpoint. Probably the trickiest part of getting the command line utilities to work is forming the URI’s to the various pieces correctly. Take a look at Table 1, which shows the URI’s for various Groove objects of interest, all of which are related. The first row shows the URI of a Space. The second row shows the URI of a Tool in that space. The third row shows the URI of a Form in that Forms tool. The fourth row shows the URI of a view in that Forms tool. Finally, the fifth row shows the URI of a record in that Forms tool. These URI’s have a great deal of common information, but there are some important differences. Table 1 – URI’s for a Space, Tool, Form, View and Record
Note how URI’s are slightly different and longer as we get more specific about what we’re interested in. If you slip up and use the wrong URI (and it’s especially easy to get that 4th field – the one that says “Spaces” or “Tools” or “Forms2”, wrong), the web method will fail with an unhelpful error. That’s another reason it’s nice to have the command line helpers – you can get some better visibility into what works more quickly than writing code. The first command line utility we’re going to use is GrooveDir. GrooveDir has a number of command line arguments (try typing “GrooveDir /?” in a cmd box), but what we want is the command that reports the workspace URI’s. This command is typed “GrooveDir /s”, which on my test system produces the following output: <GrooveDir> <Space Name='IPFormsTest' URI='/GWS/Groove/2.0/Spaces/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs'> </Space> … </GrooveDir>
To find the Tool URI, I’ll type “GrooveDir /t”, which gives me: <GrooveDir> <Tool Name='InfoPath' URI='/GWS/Groove/2.0/Tools/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq'/> … </GrooveDir>
I’m looking for a tool named “InfoPath” in the same space as the Space named “IPFormsTest, so I have to find a tool named “InfoPath” with a URI that has the same characters after “…/grooveTelespace/”. Note the subtle differences between a space URI and a tool URI (“Spaces” versus “Tools” and “ToolContainer/…”. The thing you’re looking for is the “d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs”. Finally, I need the URI’s of the records in the InfoPath Forms Tool. For that, I need the GrooveQueryFormsRecords utility. The command (typed all on one line) is GrooveQueryFormsRecords /FormsTool= ”/GWS/Groove/2.0/Tools/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq”
This will dump the xml for all the records in the Forms tool. The URI’s will look something like this: <RecordURI> /GWS/Groove/2.0/Forms2/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq/DataModelDelegate/ RecordID=-1.1372659343098586E-067 </RecordURI>
I won’t go into how you might pick a record to export. For this blog, let’s just pick the record noted above and export it. The command to do this (all on one line is): GrooveInfoPathForms /Export /RecordURI=”/GWS/Groove/2.0/Forms2/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq/DataModelDelegate/ RecordID=-1.1372659343098586E-067” /Path=C:\Users\robnovas\Documents\Temp\ExportedFromGroove.xml
This will produce a file “ExportedFromGroove.xml”. Unfortunately, if you double click this file, InfoPath is only able to open this file, at least in its present form, on the system that you exported it from Groove and only if Groove is running. Before opening the file, InfoPath will ask if it’s OK to contact the server. If you allow InfoPath to contact the server, it will open the form, again, constrained as stated. If you edit the xml in notepad, you will see the problem, as shown below. <?xml version="1.0" encoding="UTF-8"?> <?mso-infoPathSolution solutionVersion="1.0.0.1" productVersion="12.0.0" PIVersion="1.0.0.0" href="groove://groove[:221746984]C:/Users/robnovas/Documents/GWSV12Helpers/ZZZ-TestIPRoundtrip/TestRun-02/01-BuildIPForm/NewFormTemplate.xsn" name="urn:schemas-microsoft-com:office:infopath:NewFormTemplate:-myXSD-2008-03-02T13-25-10221746984" ?>
The schema for this form is in Groove and is not accessible using the URL given in the href and URN in the name. The way around this is to fixup the processing instruction so that the exported form references a schema that is accessible. The GrooveInfoPathForms command supports this with the concept of an “example form” – a form that can be used as an example to get the necessary reference. Since this form was exported from Groove, it is suitable for use as an example form for importing other forms (of the same schema) back into Groove. Let’s get another example form, suitable for importing a form into SharePoint. Fire up your SharePoint site with the Forms Library, create a form, and export this form (“Save As” to disk). Call this form ExportedFromSharePoint.xml. If you edit this form in notepad, you’ll see something like the following: <?xml version="1.0" encoding="UTF-8"?> <?mso-infoPathSolution solutionVersion="1.0.0.3" productVersion="12.0.0" PIVersion="1.0.0.0" href=http://novas-x64/sites/TestIPForm/IPFormLib/Forms/template.xsn name="urn:schemas-microsoft-com:office:infopath:IPFormLib:-myXSD-2008-03-02T13-25-10" ?>
That’s what the processing instruction will have to look like to import a form into InfoPath. So now we have two forms, ExportedFromGroove.xml, which is in a form suitable for importing a form into Groove; and ExportedFromSharePoint.xml, which is in a form suitable for importing a form into SharePoint. Now we can use the ExportedFromSharePoint.xml form as an example for a form exported from Groove that we will import into SharePoint. The command to export the form from Groove is (all on one line): GrooveInfoPathForms /Export /RecordURI=”/GWS/Groove/2.0/Forms2/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq/DataModelDelegate/ RecordID=-1.1372659343098586E-067” /Path=C:\Users\robnovas\Documents\Temp\ExportedFormDestinedForSharePoint.xml /ExamplePath=C:\Users\robnovas\Documents\Temp\ExportedFromSharePoint.xml
ExportedFormDestinedForSharePoint.xml now is properly setup to be able to be uploaded into the SharePoint Forms Library. You should be able to upload this form to your SharePoint Form Library and open it with no trouble. Now, let’s import the form exported from SharePoint into Groove. Just as an experiment, try to import the form without specifying an example form (type the command all on one line): GrooveInfoPathForms /Import /FormURI="/GWS/Groove/2.0/Forms2/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq/DataModelDelegate/ FormID=-4.41257738669127E+044" /Path=C:\Users\robnovas\Documents\Temp\ExportedFromSharePoint.xml
You’ll get the following error: Unable to set the 'Forms_Tool_IPContents' field because the document content is invalid.
Now, try importing the form again but this time specify the ExportedFromGroove.xml form as an example (type the command all on one line): GrooveInfoPathForms /Import /FormURI="/GWS/Groove/2.0/Forms2/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContaner/depnrjn9xqxgq/DataModelDelegate/ FormID=-4.41257738669127E+044" /Path=C:\Users\robnovas\Documents\Temp\ExportedFromSharePoint.xml /ExamplePath=c:\Users\robnovas\Documents\Temp\ExportedFromGroove.xml
This time the command returns the URI of the form created in Groove: <GrooveInfoPathForms> <Import URI='/GWS/Groove/2.0/Forms2/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq/DataModelDelegate/ RecordID=-1.5660662740611548E-088'/> </GrooveInfoPathForms>
Hopefully this will help you get on your way towards exporting and importing Groove InfoPath forms. Another idea I’m kicking around is how to pick which forms to export. What I’m thinking of there is to use views to impose a kind of workflow on forms and to move a form from one view to another as the workflow progresses. The views would be something like this – Draft, Submitted, Exported, Accepted. A user would create a form in the Draft view. “Submitting” the form would move it to the Submitted view. Exporting the form would move it to the Exported view. And the back end system accepting the form would move it to the Accepted view. More to come. Exporting the template from GrooveYou can also recover the InfoPath Form template from the Groove InfoPath Forms tool. To do that, you need the URI of the Form. The command to report the Form URI’s of a Forms tool is: GrooveQueryForms /FormsTool=”/GWS/Groove/2.0/Tools/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq”
This produces the xml shown below: <?xml version="1.0" encoding="utf-8"?> <QueryFormsResult URI="/GWS/Groove/2.0/Tools/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq" Name="InfoPath"> <Forms> <Form Name="NewFormTemplate" ID="-4.41257738669127E+044" URI="/GWS/Groove/2.0/Forms2/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq/DataModelDelegate/ FormID=-4.41257738669127E+044" /> </Forms> <Views> <View Name="View_1" ID="2.711619205752946E-056" URI="/GWS/Groove/2.0/Forms2/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq/DataModelDelegate/ ViewID=2.711619205752946E-056" /> </Views> </QueryFormsResult>
What we want is the Form URI for the NewFormTemplate form. We use that URI in another command, as shown next: GrooveInfoPathForms /Template /FormURI=”/GWS/Groove/2.0/Forms2/ grooveTelespace/d99raev3ii89vnwxiec5i5pxia2uzmqi3tgnjxs/ ToolContainer/depnrjn9xqxgq/DataModelDelegate/ FormID=-4.41257738669127E+044” /Path=”C:\Users\robnovas\Documents\Temp\ExportedTemplate.xsn”
This creates the ExportedTemplate.xsn file, which is the forms template that was used to design this form in the Groove InfoPath Forms tool. |
|
|