<?xml version="1.0"?>
<!-- RSS generated by Radio UserLand v8.0.8 on Mon, 23 Feb 2004 01:33:54 GMT -->
<rss version="2.0">
	<channel>
		<title>Paresh Suthar: Groove Programming Tips &amp; Tricks</title>
		<link>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/</link>
		<description>Techniques to develop better tools in Groove</description>
		<language>en-us</language>
		<copyright>Copyright 2004 Paresh Suthar</copyright>
		<lastBuildDate>Mon, 23 Feb 2004 01:33:54 GMT</lastBuildDate>
		<docs>http://backend.userland.com/rss</docs>
		<generator>Radio UserLand v8.0.8</generator>
		<managingEditor>paresh@suthar.com</managingEditor>
		<webMaster>paresh@suthar.com</webMaster>
		<category domain="http://www.weblogs.com/rssUpdates/changes.xml">rssUpdates</category> 
		<skipHours>
			<hour>23</hour>
			<hour>0</hour>
			<hour>1</hour>
			<hour>2</hour>
			<hour>3</hour>
			<hour>4</hour>
			<hour>5</hour>
			<hour>18</hour>
			</skipHours>
		<cloud domain="radio.xmlstoragesystem.com" port="80" path="/RPC2" registerProcedure="xmlStorageSystem.rssPleaseNotify" protocol="xml-rpc"/>
		<ttl>60</ttl>
		<item>
			<description>&lt;STRONG&gt;Release objects cached in GrooveRunTimeData when they are no longer needed&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;You can either call the RemoveItem method (to remove one item at a time) or you can call the RemoveAllItems method to accomplish this.</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2003/02/15.html#a250</guid>
			<pubDate>Sat, 15 Feb 2003 14:43:01 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=250</comments>
			</item>
		<item>
			<description>&lt;P&gt;&lt;STRONG&gt;Implement COM objects in script&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;Among the variety of powerful things that Groove&apos;s ScriptFreeThreaded component can do, one of the more interesting ones is the ability to implement CoCreate&apos;able objects in script.&amp;nbsp; The &lt;A href=&quot;http://www.groove.net/devzone/&quot;&gt;Groove Platform GDK&lt;/A&gt; contains a sample called YourApp10 that shows how to do this, so I will just summarize the main points.&amp;nbsp; Note that if you don&apos;t know much about COM or writing IDL, go get this &lt;A href=&quot;http://www.amazon.com/exec/obidos/tg/detail/-/0201634465/qid=1036416906/sr=8-3/ref=sr_8_3/002-9250322-5770444?v=glance&amp;amp;n=507846&quot;&gt;book&lt;/A&gt; and read it.&lt;BR&gt;&lt;BR&gt;&lt;U&gt;Write IDL for the COM object&lt;/U&gt;&lt;BR&gt;To be a good citizen to early and late binding clients, you should define &lt;A href=&quot;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/automat/htm/chap2_6l5x.asp&quot;&gt;dual&lt;/A&gt; interfaces for non-event interfaces.&amp;nbsp; You should also have 2 flavors of event interfaces, 1 for early bound clients that derives from IUnknown and 1 for late bound clients that is a dispinterface.&amp;nbsp; You should also define a CoClass to publish the interfaces implemented by the COM object.&amp;nbsp; Note that [in, out] and [out] parameters are not supported for methods.&lt;BR&gt;&lt;BR&gt;&lt;U&gt;Define OSD so that the COM object can be CoCreate&apos;d&lt;/U&gt;&lt;BR&gt;&amp;lt;SOFTPKG NAME=&quot;com.yourcompany.xxx.YourCOMObject_GSL&quot; VERSION=&quot;1,0,0,0&quot;&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;lt;IMPLEMENTATION&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;CODEBASE HREF=&quot;&lt;A href=&apos;http://components.yourcompany.com/xxx/YourCOMObject.gsl&quot;/&apos;&gt;&lt;a href=&quot;http://components.yourcompany.com/xxx/YourCOMObject.gsl&quot;&gt;http://components.yourcompany.com/xxx/YourCOMObject.gsl&lt;/a&gt;&quot;/&lt;/A&gt;&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;g:Install Type=&quot;Import To XSS&quot; DatabaseURI=&quot;$TEMPLATESURI$&quot; DocumentName=&quot;YourCOMObject.gsl&quot; SchemaURI=&quot;$DEFAULTSCHEMA$&quot;/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;g:Factory Name=&quot;Open&quot; Type=&quot;XML Document&quot; DatabaseURI=&quot;$TEMPLATESURI$&quot; DocumentName=&quot;YourCOMObject.gsl&quot;/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;g:Registry Command=&quot;Add&quot; Hive=&quot;HKCR&quot; Key=&quot;clsid\{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}&quot; Value=&quot;&quot; Data=&quot;Your COM Object&quot; Type=&quot;String&quot;/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;g:Registry Command=&quot;Add&quot; Hive=&quot;HKCR&quot; Key=&quot;clsid\{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\InprocServer32&quot; Value=&quot;&quot; Data=&quot;$GROOVEBIN$\GrooveCommonComponents.dll&quot; Type=&quot;String&quot;/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;g:Registry Command=&quot;Add&quot; Hive=&quot;HKCR&quot; Key=&quot;clsid\{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\InprocServer32&quot; Value=&quot;ThreadingModel&quot; Data=&quot;Both&quot; Type=&quot;String&quot;/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;g:Registry Command=&quot;Add&quot; Hive=&quot;HKCR&quot; Key=&quot;clsid\{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\URL&quot; Value=&quot;&quot; Data=&quot;&lt;A href=&quot;http://components.yourcompany.com/xxx/YourCOMObject.osd?Package=com.yourcompany.xxx.YourCOMObject_GSL&amp;amp;amp;Version=1,0&amp;amp;amp;Factory=Open&quot;&gt;&lt;a href=&quot;http://components.yourcompany.com/xxx/YourCOMObject.osd?Package=com.yourcompany.xxx.YourCOMObject_GSL&amp;amp&quot;&gt;http://components.yourcompany.com/xxx/YourCOMObject.osd?Package=com.yourcompany.xxx.YourCOMObject_GSL&amp;amp&lt;/a&gt;;amp;Version=1,0&amp;amp;amp;Factory=Open&lt;/A&gt;&quot; Type=&quot;String&quot;/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;g:Registry Command=&quot;Add&quot; Hive=&quot;HKCR&quot; Key=&quot;YourCOMObjects.YourCOMObjectProgID\CLSID&quot; Value=&quot;&quot; Data=&quot;{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}&quot; Type=&quot;String&quot;/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/IMPLEMENTATION&amp;gt;&lt;BR&gt;&amp;lt;/SOFTPKG&amp;gt;&lt;BR&gt;&lt;BR&gt;&lt;U&gt;Create a .gsl file for the COM object&lt;/U&gt;&lt;BR&gt;This script file should import the type library for your COM object, as well as any other dependent type libraries.&amp;nbsp; &amp;nbsp;You import type libraries by having the following statement: 
&lt;BLOCKQUOTE dir=ltr style=&quot;MARGIN-RIGHT: 0px&quot;&gt;&amp;lt;TYPELIB LIBID=&quot;{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFE}&quot; NAME=&quot;YourCOMObjectTypeLibrary&quot; MAJORVER=&quot;1&quot; MINORVER=&quot;0&quot;/&amp;gt;&lt;/BLOCKQUOTE&gt;Your script file should implement the interfaces as described by the coclass (at least).&amp;nbsp; You implement interfaces by having the following statement:&lt;BR&gt;&lt;BR&gt;
&lt;BLOCKQUOTE dir=ltr style=&quot;MARGIN-RIGHT: 0px&quot;&gt;&amp;lt;IMPLEMENTS Default=&quot;1&quot; IID=&quot;{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}&quot; LIBID=&quot;{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFE}&quot;&amp;gt; &lt;/BLOCKQUOTE&gt;Note that the Default attribute should only be used for one of the implemented interfaces, and omitted from all other implemented interface.&amp;nbsp; Also note that to return HRESULT values, you should use the &lt;A href=&quot;http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/09/12.html&quot;&gt;SetCurrentError&lt;/A&gt; method.&lt;BR&gt;&lt;BR&gt;&lt;U&gt;Global &amp;amp; instance&amp;nbsp;data storage&lt;/U&gt;&lt;BR&gt;You should not define/use global variables because of performance reasons and the fact that they are not thread safe/&lt;A href=&quot;http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/09/27.html&quot;&gt;accessible&lt;/A&gt;.&amp;nbsp; Instead you should use GrooveRunTimeData and/or &lt;A href=&quot;http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/21.html#a72&quot;&gt;ScriptSharedObjectTables&lt;/A&gt;.</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/11/04.html#a207</guid>
			<pubDate>Mon, 04 Nov 2002 12:59:21 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=207</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Don&apos;t use JavaScript classes/objects for storage&amp;nbsp;in ScriptFreeThreadedComponents&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;Any objects that are allocated by calling the &quot;new&quot; operator have thread affinity - this means that if the thread 1 creates an instance of a JavaScript class, only thread 1 can access/use it.&amp;nbsp; Instead use &lt;A href=&quot;http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/21.html#a72&quot;&gt;shared object tables&lt;/A&gt; for scalar types&amp;nbsp;or&amp;nbsp;COM objects implemented in script when instance method invocation is required.</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/09/27.html#a168</guid>
			<pubDate>Fri, 27 Sep 2002 13:50:03 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=168</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Return HRESULTs from script languages that implement COM interfaces&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;Groove&apos;s script host provides an object called GrooveErrorFunctions that you can use call the SetCurrentError method with an HRESULT value and string description.&amp;nbsp; The effect is that an exception is thrown to the caller with the value/description, so the caller should have exception handling code around the method call.&lt;BR&gt;&lt;BR&gt;&lt;U&gt;Example&lt;/U&gt;&lt;BR&gt;function&amp;nbsp;FindPerson&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; i_FirstName,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; i_LastName&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;BR&gt;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (i_FirstName&amp;nbsp;== &quot;&quot;) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp;&amp;nbsp;Return E_INVALIDARG (hex value = 0x80000003, integral value = -2147024809)&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GrooveErrorFunctions.SetCurrentError(-2147024809, &quot;First name required!&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (i_LastName&amp;nbsp;== &quot;&quot;) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp;&amp;nbsp;Return E_INVALIDARG (hex value = 0x80000003, integral value = -2147024809)&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GrooveErrorFunctions.SetCurrentError(-2147024809, &quot;Last name required!&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;var Person = null;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp;&amp;nbsp;Some code here&amp;nbsp;to find person&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch (e)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp;&amp;nbsp;Return&amp;nbsp;E_FAIL (hex value = 0x80004005, integral value = -2147467259)&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GrooveErrorFunctions.SetCurrentError(-2147467259, &quot;Unexpected error!&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Person;&lt;BR&gt;&amp;nbsp;&amp;nbsp; }</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/09/12.html#a141</guid>
			<pubDate>Thu, 12 Sep 2002 13:50:12 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=141</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Use globals in script sparingly, as it affects performance&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;Whenever a variable is referenced in script code, the context of the variable is determined first, which means some sort of lookup.&amp;nbsp; The use of a local variable reduces the surface area of the the lookup to the current function/method, while a global variable has the surface area of the entire CDATA section.&lt;BR&gt;&lt;BR&gt;The following list of ways to store global data is prioritized, with the first item being the most performant and the last item being the least performant:&lt;BR&gt;
&lt;OL dir=ltr&gt;
&lt;LI&gt;
&lt;DIV style=&quot;MARGIN-RIGHT: 0px&quot;&gt;GrooveRunTimeData (ScriptFreeThreadedComponent only)&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV style=&quot;MARGIN-RIGHT: 0px&quot;&gt;SharedObjectTable&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV style=&quot;MARGIN-RIGHT: 0px&quot;&gt;Global variables&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;&lt;BR&gt;</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/09/09.html#a128</guid>
			<pubDate>Mon, 09 Sep 2002 13:25:32 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=128</comments>
			</item>
		<item>
			<description>&lt;P&gt;&lt;STRONG&gt;Use&amp;nbsp;the existence of properties/attributes as a boolean value rather than&amp;nbsp;the actual value.&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;Instead of writing code like this:&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;PropertyList.SetProperty(&quot;Initialized&quot;, true);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;&amp;nbsp;&amp;nbsp; var Initialized = false;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (PropertyList.PropertyExists(&quot;Initialized&quot;))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Initialized = PropertyList.OpenValue(&quot;Initialized&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp; .&lt;BR&gt;&amp;nbsp;&amp;nbsp; .&lt;BR&gt;&lt;BR&gt;Write code like this:&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;PropertyList.SetProperty(&quot;Initialized&quot;, true);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;&amp;nbsp;&amp;nbsp; var Initialized =&amp;nbsp;PropertyList.PropertyExists(&quot;Initialized&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp; .&lt;BR&gt;&amp;nbsp;&amp;nbsp; .&lt;BR&gt;&lt;/P&gt;</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/09/05.html#a118</guid>
			<pubDate>Thu, 05 Sep 2002 13:56:00 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=118</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Watch out for&amp;nbsp;redundant event&amp;nbsp;subscriptions when using Groove&apos;s ScriptHost components&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;If you&amp;nbsp;define a component connection for Groove&apos;s ScriptHost components, the events&amp;nbsp;provided by the component are automatically subscribed to:&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;lt;g:ComponentConnections&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;g:Connection ConnectionID=&quot;0&quot; Name=&quot;MyDataModelDelegate&quot;/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;lt;/g:ComponentConnections&amp;gt;&lt;BR&gt;&lt;BR&gt;In the case above, event handlers can be implemented in JavaScript by defining functions that use &quot;MyDataModelDelegate_&quot; as a prefix (e.g. &quot;function MyDataModelDelegate_OnSomeEvent&quot;).&lt;BR&gt;&lt;BR&gt;If you&amp;nbsp;have&amp;nbsp;JavaScript code defined in the&amp;nbsp;code block that attempts to manually subscribe for events using the ConnectObject/Advise method, you will be&amp;nbsp;providing the prefix for defining functions.&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; function Initialize ()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var pITool = PropertyList.OpenProperty(PROPERTY_TOOL);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var pIDelegateComponent = pITool.OpenDelegateComponent();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var pIMyDataModelDelegate = pIDelegateComponent.IMyDataModelDelegate;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ConnectObject(pIMyDataModelDelegate, &quot;pIMyDataModelDelegate_&quot;, true);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;In the case above, event handlers can be implemented in JavaScript by defining functions that use &quot;pIMyDataModelDelegate_&quot; as a prefix (e.g. &quot;function pIMyDataModelDelegate_OnSomeEvent&quot;).&lt;BR&gt;&lt;BR&gt;The problem to watch out for is when you have both a component connection and code that manually subscribes for events from the same component - the ScriptHost component will always perform component connection based event subscriptions first.&amp;nbsp; Additionally, any subsequent&amp;nbsp;attempts to subscribe for events will not actually do anything, and no errors or warnings will be given.&amp;nbsp; What this means is that if you only define an event handler for the manual subscription, those events will never get triggered.&lt;BR&gt;</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/27.html#a97</guid>
			<pubDate>Tue, 27 Aug 2002 14:41:23 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=97</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Use Javascript and the &quot;My Templates&quot; directory to rapidly prototype&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;When you are developing tools that use Groove&apos;s UI components, there is no faster way to prototype than by using the &quot;My Templates&quot; directory.&amp;nbsp; What makes it so productive is that any properly formed .tpl file that is placed into this directory (e.g. &quot;c:\program files\groove networks\groove\data\my templates&quot;) can immediately be added to a space.&amp;nbsp; Additionally, any changes made to the .tpl file will immediately be seen upon add a new instance of the tool to the space (vs. having to overlay templates using something like Groove Database Navigator).&lt;BR&gt;&lt;BR&gt;This technique only works for .tpl files,&amp;nbsp;it will not work for .gsl or .xml files.&amp;nbsp; One thing to keep in mind is that if you need to modify a .tpl file that has dependencies on .gsl or .xml files, once the tool has been injected (via .grv file), you can copy the .tpl file to the &quot;My Templates&quot; directory and use it for rapid prototyping -&amp;nbsp;just make sure to copy the changes back to the original .tpl file.&lt;BR&gt;
&lt;P&gt;For more information, check out the Groove Platform GDK documentation.&lt;/P&gt;</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/26.html#a94</guid>
			<pubDate>Mon, 26 Aug 2002 13:47:11 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=94</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Use Groove tracing to help debug tools&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;The Groove platform GDK ships with the Groove Trace Window which is an application that can be used to have information logged/displayed while debugging a tool.&amp;nbsp; Using the tracing facilities is pretty simple:&lt;BR&gt;&lt;BR&gt;var pIGrooveTraceControl = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GrooveScriptFunctions.CreateNewObject(&quot;GrooveTraceControlLib.GrooveTraceControl&quot;);&lt;BR&gt;pIGrooveTraceControl.SendToTraceWindow(&quot;This is a test!&quot;);&lt;BR&gt;&lt;BR&gt;If the Groove Trace Window is not open/running, then&amp;nbsp;any SendToTraceWindow method calls result in nothing being done (i.e. not a performance hit).&amp;nbsp; Once the Groove Trace Window is opened, then all calls to the SendToTraceWindow method call will produce output and it will be serialized.&amp;nbsp; Obviously this is a debugging aid, and all references to it should be removed prior to releasing your tool.</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/23.html#a84</guid>
			<pubDate>Fri, 23 Aug 2002 12:50:13 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=84</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Hold a strong reference to the&amp;nbsp;tool and/or telespace, not just the data model delegate(DMD)&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;When writing tools that subscribe to DMD events provided by other tools in the &lt;U&gt;same&lt;/U&gt; telespace, you (currently) must hold a strong reference to the tool in which the DMD lives to ensure that the tool does not get unloaded. &lt;BR&gt;&lt;BR&gt;When writing tools that subscribe to DMD events provided by&amp;nbsp;other tools in&amp;nbsp;&lt;U&gt;other&lt;/U&gt; telespaces, you (currently) must hold a strong reference to the tool in which the DMD lives&amp;nbsp;&lt;EM&gt;and&lt;/EM&gt;&amp;nbsp;the telespace in which that tool lives,&amp;nbsp;to ensure that the both the tool and telespace do not get unloaded.&lt;BR&gt;&lt;BR&gt;Groove has caching algorithms that periodically unload tools and telespaces to help efficiently manage memory usage - but any tools and/or telespaces that have strong references held on them will prevent such unloading.&amp;nbsp; Obviously this means that the memory usage will not go down until the strong references on the tools and/or telespaces are released.&lt;BR&gt;</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/22.html#a78</guid>
			<pubDate>Thu, 22 Aug 2002 13:48:49 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=78</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Use CreateDelta instead of OpenTransaction(false) for write operations&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;Many of you are familiar with the following&amp;nbsp;pattern/style&amp;nbsp;of code:&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var pITelespace = PropertyList.OpenProperty(PROPERTY_TELESPACE).Telespace;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var pITransaction = pITelespace.OpenTransaction(false);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pIRecord.SetField(&quot;Name&quot;, &quot;Paresh&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pIRecord.SetField(&quot;Company&quot;, &quot;Groove Networks&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pITransaction.Commit();&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp; catch&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pITransaction.Abort();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;There are 2&amp;nbsp;problems with this pattern/style of coding:&lt;BR&gt;&lt;BR&gt;1) There will be 2 deltas disseminated to all other endpoints (which is less efficient)&lt;BR&gt;2) Any undo/redo of the operations for Dynamics sequencing will not treat the 2 deltas as one transactional command.&lt;BR&gt;&lt;BR&gt;Since the intent of the code above is to group&amp;nbsp;all of&amp;nbsp;the write operations as one transactional command, the appropriate approach is to have Dynamics Manager govern the execution of the write operations.&amp;nbsp; This is accomplished by using the CreateDelta method:&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;var pIDynamicsManager =&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PropertyList.OpenProperty(PROPERTY_DYNAMICS_MANAGER).DynamicsManager;&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pIDelta = pIDynamicsManager.CreateDelta();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pIRecord.SetField(&quot;Name&quot;, &quot;Paresh&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pIRecord.SetField(&quot;Company&quot;, &quot;Groove Networks&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pIDelta.Commit();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp; catch&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pIDelta.Abort();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/21.html#a74</guid>
			<pubDate>Wed, 21 Aug 2002 13:52:30 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=74</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Use&amp;nbsp;shared object tables to hold sets of data with GrooveRunTimeData&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;Shared Object Tables are process wide object tables that can be used to store references to scalar or object types.&amp;nbsp; They can be created with or without a developer specified name, but keep in mind that if a name is used, developers must think about other instances of their tool running on the same device (cross account/telespace/tool)&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;[code fragment for performing deletion of records in recordset]&lt;BR&gt;&lt;/EM&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; Create shared object table that will use record ids as index and record&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; types as values.&amp;nbsp; This shared object table will be primarily used to&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; provide information about a record upon receipt of asynchronous&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; deletion notifications&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pISharedObjectTable = GrooveScriptFunctions.OpenSharedObjectTable(&quot;&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp; GrooveRunTimeData.SetItem(&quot;DeletedRecordSharedObjectTable&quot;, pISharedObjectTable); &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; Get record and clone it&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pIRecord = RecordSetEngine.OpenRecord(i_ID);&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pIDeletedRecord = pIRecord.Clone(); &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; Add cloned record to shared object table&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pISharedObjectTable = GrooveRunTimeData.GetItem(&quot;DeletedRecordSharedObjectTable&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp; pISharedObjectTable[i_ID] = pIDeletedRecord;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp;&amp;nbsp; Remove record from recordset&lt;BR&gt;&amp;nbsp;&amp;nbsp; RecordSetEngine.RemoveRecord(i_ID);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;[code fragment from OnRecordSetChanged asynchronous event handler]&lt;/EM&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; case GrooveRecordSetChangeType_Removed:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; Get record id&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var RecordID = i_pIRecordIDEnum.OpenNext();&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; Get cached reference to record&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var pISharedObjectTable = GrooveRunTimeData.GetItem(&quot;DeletedRecordSharedObjectTable&quot;);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var pIRecord = pISharedObjectTable[RecordID];&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; Remove cached reference to record&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pISharedObjectTable[RecordID] = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;BR&gt;
&lt;P&gt;&lt;/P&gt;</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/21.html#a72</guid>
			<pubDate>Wed, 21 Aug 2002 13:12:23 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=72</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Sprinkle ASSERTs in your code when debugging free-threaded script code instead of breakpoints&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;Often you will find that it is difficult (if not impossible) to set breakpoints in free-threaded script code - I haven&apos;t figured out why yet.&amp;nbsp; I have found that by placing the statement &quot;GrooveDebugFunctions.Assert(false, &quot;&quot;);&quot; at the location I would have normally set the breakpoint, that the script debugger (Visual Interdev in my case) always comes up and allows me to debug my code.</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/20.html#a68</guid>
			<pubDate>Tue, 20 Aug 2002 12:57:12 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=68</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Explicitly ask for&amp;nbsp;an interface after getting it from PropertyList&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;When the PropertyList is used from script code to get an interface, one must keep in mind that the default IDispatch interface is returned from such a request, and in some cases this means you will not get the interface you asked for.&amp;nbsp; For example:&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; The following line will get an IGrooveAccount interface&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pIAccount = PropertyList.OpenProperty(PROPERTY_ACCOUNT);&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; The following line will also get an IGrooveAccount interface,&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; but this is not what you would expect&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pITelespaceProvider = PropertyList.OpenProperty(PROPERTY_TELESPACE_PROVIDER);&amp;nbsp;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; This is the recommend way for both to make sure the expected&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;//&quot;&gt;//&lt;/a&gt; &amp;nbsp; interface is returned&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pIAccount = PropertyList.OpenProperty(PROPERTY_ACCOUNT).Account;&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pITelespaceProvider = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PropertyList.OpenProperty(PROPERTY_TELESPACE_PROVIDER).TelespaceProvider; &lt;BR&gt;&lt;BR&gt;</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/19.html#a61</guid>
			<pubDate>Mon, 19 Aug 2002 13:05:18 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=61</comments>
			</item>
		<item>
			<description>&lt;STRONG&gt;Use the &quot;GrooveTelespace&quot; object as&amp;nbsp;reference to a tool&apos;s telespace&lt;/STRONG&gt;&lt;BR&gt;&lt;BR&gt;Starting with Groove v2.1, whenever you are using the &lt;U&gt;free threaded&lt;/U&gt; version of the ScriptHost to write script code for your tool, you can now write code like:&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pITransaction = GrooveTelespace.OpenTransaction(true);&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; - instead of -&lt;/EM&gt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; var pITelespace = PropertyList.OpenProperty(PROPERTY_TELESPACE).Telespace; &lt;BR&gt;&amp;nbsp;&amp;nbsp; var pITransaction = pITelespace.OpenTransaction(true);&lt;BR&gt;&lt;BR&gt;</description>
			<guid>http://radio.weblogs.com/0111019/categories/grooveProgrammingTipsTricks/2002/08/19.html#a60</guid>
			<pubDate>Mon, 19 Aug 2002 12:50:42 GMT</pubDate>
			<comments>http://radiocomments.userland.com/comments?u=111019&amp;amp;p=60</comments>
			</item>
		</channel>
	</rss>
