<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7690408</id><updated>2011-12-29T20:19:35.308+08:00</updated><category term='EPM'/><category term='aspnet'/><category term='xml'/><category term='iis'/><category term='web'/><category term='Reporting Service'/><category term='Office'/><category term='security'/><category term='programming'/><category term='SQL Server 2005'/><category term='Windows Server 2008'/><category term='msi'/><category term='DotNet'/><category term='Windows'/><category term='Generics'/><category term='sql server'/><category term='sharepoint'/><category term='csharp'/><category term='Firefox'/><category term='Product Development'/><category term='sql'/><category term='Expression'/><category term='web service'/><category term='Fiddler'/><category term='Visual Basic'/><category term='design'/><category term='command line'/><category term='project'/><category term='visualstudio'/><category term='WPF'/><category term='management'/><title type='text'>Jonathan Yong</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default?start-index=101&amp;max-results=100'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>175</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7690408.post-4102728367419248671</id><published>2011-05-20T11:28:00.003+08:00</published><updated>2011-05-20T11:38:11.870+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Expression'/><title type='text'>Installing Expresion Blend 4 SP1</title><content type='html'>If you get the message "Upgrade not applicable" when trying to install Expression Blend 4 SP1, this is most likely because you already have the Windows Phone Development Tool installed.&lt;br /&gt;&lt;br /&gt;WPDT will install a copy of Blend with SP1 to design Windows Phone Silverlight app.&lt;br /&gt;&lt;br /&gt;If your version of Blend is : 4.0.20901.0, then you already have the SP1 installed.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=17872a3a-4620-4b87-9d62-f29173d12625"&gt;Expresion Blend 4 SP 1 Download page&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-4102728367419248671?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/4102728367419248671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=4102728367419248671' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4102728367419248671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4102728367419248671'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2011/05/installing-expresion-blend-4-sp1.html' title='Installing Expresion Blend 4 SP1'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-142355611972613159</id><published>2011-05-09T00:58:00.002+08:00</published><updated>2011-05-09T00:59:56.872+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visualstudio'/><title type='text'>Running Visual Studio Load Test</title><content type='html'>If you are creating a load test in Visual Studio, the load test result will be saved to a SQL Server database.&lt;br /&gt;&lt;br /&gt;There is a one time setup which you need to do in order to save the result into the database.&lt;br /&gt;&lt;br /&gt;1) &lt;b&gt;You need to create the database schema&lt;/b&gt; in a SQL Server database. To do this, run the following sql script in SQL Server to create the database:&lt;br /&gt;&lt;i&gt;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\loadtestresultsrepository.sql&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Note : Use 'Program Files' if you are on 32bit. Use 'Program Files (x86)' if you are on 64bit.&lt;br /&gt;Use 'Microsoft Visual Studio 10.0' if you are using Visual Studio 2010. Use 'Microsoft Visual Studio 9.0' if you are using Visual Studio 2008.&lt;br /&gt;&lt;br /&gt;The default database name is 'LoadTest2010' (for VS 2010) and 'LoadTest' (for VS 2008).&lt;br /&gt;&lt;br /&gt;2) &lt;b&gt;You need to configure the database connection string&lt;/b&gt; in Visual Studio so that the load test know where to save the test result. To do this, &lt;br /&gt;go to menu Test -&gt; Manage Test Controller, then click on the browse button to enter you connection string.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-8hmWSebA7Wc/TcbL1NkTTVI/AAAAAAAAAGM/3rlHb4Vc_o4/s1600/configure_testresult_db.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 345px;" src="http://4.bp.blogspot.com/-8hmWSebA7Wc/TcbL1NkTTVI/AAAAAAAAAGM/3rlHb4Vc_o4/s400/configure_testresult_db.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5604390901344587090" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You only need to do these steps once. The same database will be used for all load tests for all projects.&lt;br /&gt;&lt;br /&gt;If you do not do the above steps, you won't be able to see result after you run the load test.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-142355611972613159?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/142355611972613159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=142355611972613159' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/142355611972613159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/142355611972613159'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2011/05/running-visual-studio-load-test.html' title='Running Visual Studio Load Test'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-8hmWSebA7Wc/TcbL1NkTTVI/AAAAAAAAAGM/3rlHb4Vc_o4/s72-c/configure_testresult_db.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-3561719813720987609</id><published>2011-05-09T00:54:00.001+08:00</published><updated>2011-05-09T00:56:29.851+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visualstudio'/><category scheme='http://www.blogger.com/atom/ns#' term='Fiddler'/><title type='text'>Save Fiddler Session as Visual Studio Web Test</title><content type='html'>Fiddler enable you save a recording session as 'Visual Sudio Web Test'. The web test can then be added to the Visual Studio test project.&lt;br /&gt;This function used to be acceesible from menu File -&gt; Save.&lt;br /&gt;&lt;br /&gt;However, if you are using a newer build (release since early 2011), this function has been moved to File -&gt; Export Session. You can choose 'Visual Studio Web Test' from the dialog drop down.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-fBasDcZGcGE/TcbLFGEorSI/AAAAAAAAAGE/Uuc8fok_cik/s1600/fiddler_export_as_webtest.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 164px;" src="http://1.bp.blogspot.com/-fBasDcZGcGE/TcbLFGEorSI/AAAAAAAAAGE/Uuc8fok_cik/s400/fiddler_export_as_webtest.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5604390074699001122" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-3561719813720987609?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/3561719813720987609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=3561719813720987609' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/3561719813720987609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/3561719813720987609'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2011/05/save-fiddler-session-as-visual-studio.html' title='Save Fiddler Session as Visual Studio Web Test'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-fBasDcZGcGE/TcbLFGEorSI/AAAAAAAAAGE/Uuc8fok_cik/s72-c/fiddler_export_as_webtest.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-917026318382373848</id><published>2011-02-20T12:01:00.003+08:00</published><updated>2011-02-20T12:07:13.511+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><title type='text'>Hidden configuration for Firefox</title><content type='html'>There is another way to tweak configuration in Firefox. Type 'about:config' in the location bar and hit &amp;lt;enter&amp;gt;. Firefox will then display a configuration screen which has more configuration options than you can find in the normal Tools -&gt; Options.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-917026318382373848?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/917026318382373848/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=917026318382373848' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/917026318382373848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/917026318382373848'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2011/02/hidden-configuration-for-firefox.html' title='Hidden configuration for Firefox'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-8984392420788139926</id><published>2010-06-20T12:12:00.026+08:00</published><updated>2010-06-20T14:25:42.795+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visualstudio'/><category scheme='http://www.blogger.com/atom/ns#' term='aspnet'/><category scheme='http://www.blogger.com/atom/ns#' term='msi'/><title type='text'>Creating a Web Setup Project for asp.net Application Using Visual Studio</title><content type='html'>This is a tutorial how you can create a simple web setup project for your asp.net application. We will also add a new wizard step into the msi setup wizard to allow user to choose which environment he is installing and the msi will deploy the appropriate web.config specific for that environment.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. Create a new Web Application project in Visual Studio&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jRUlOncToWc/TB2X6rLvkgI/AAAAAAAAADE/9LA9D0NnS_4/s1600/01-create_web_app.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 284px;" src="http://1.bp.blogspot.com/_jRUlOncToWc/TB2X6rLvkgI/AAAAAAAAADE/9LA9D0NnS_4/s400/01-create_web_app.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484706955487318530" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2. Insert the following appSetting into web.config&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jRUlOncToWc/TB2YmuloIvI/AAAAAAAAADM/dX0AIYddjGM/s1600/02-webconfig.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 140px;" src="http://2.bp.blogspot.com/_jRUlOncToWc/TB2YmuloIvI/AAAAAAAAADM/dX0AIYddjGM/s400/02-webconfig.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484707712315433714" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;3. Copy paste the web.config 3 times and rename to the following file name:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jRUlOncToWc/TB2Z8ypZ3mI/AAAAAAAAADU/g-D30OHzUr8/s1600/03-webconfig_env.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 243px; height: 241px;" src="http://4.bp.blogspot.com/_jRUlOncToWc/TB2Z8ypZ3mI/AAAAAAAAADU/g-D30OHzUr8/s400/03-webconfig_env.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484709190873767522" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Each of the 3 files contain configuration that is specific to their environment(development, SIT and production). You can add more configuration to the config file depend on your application need. We will use these files in the web setup project later.&lt;br /&gt;&lt;br /&gt;4. Update each of the new web.config to reflect its environment:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jRUlOncToWc/TB2dM1wuArI/AAAAAAAAADc/25fgRi-SfH8/s1600/04-webconfig_env2.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 383px; height: 204px;" src="http://1.bp.blogspot.com/_jRUlOncToWc/TB2dM1wuArI/AAAAAAAAADc/25fgRi-SfH8/s400/04-webconfig_env2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484712765122544306" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;5. Add a new Web Setup Project into the solution.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jRUlOncToWc/TB2f7lBcTlI/AAAAAAAAADk/klPMx_w-n4A/s1600/05-add_web_setup_project.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 255px;" src="http://2.bp.blogspot.com/_jRUlOncToWc/TB2f7lBcTlI/AAAAAAAAADk/klPMx_w-n4A/s400/05-add_web_setup_project.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484715767106391634" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;After you add the Setup project,&lt;br /&gt;Select the Web Application Folder, in the property window, modify the virtual directory name. This is the default virtual directory name which will be installed into IIS. You can change this later during the installation. If you cannot see the Web Application Folder, select the Web Setup project, in visual studio menu, go to View -&gt; Editor -&gt; File System.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jRUlOncToWc/TB2wFrTsgyI/AAAAAAAAAFc/GCyNTKK4O0Q/s1600/05b-set_virtualdir.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 349px;" src="http://2.bp.blogspot.com/_jRUlOncToWc/TB2wFrTsgyI/AAAAAAAAAFc/GCyNTKK4O0Q/s400/05b-set_virtualdir.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484733532778300194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6. Right click in the Web Setup project and select Add -&gt; Project output.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jRUlOncToWc/TB2gOR2PEBI/AAAAAAAAADs/bxuekTCiSCI/s1600/06-add_project_output.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 363px;" src="http://4.bp.blogspot.com/_jRUlOncToWc/TB2gOR2PEBI/AAAAAAAAADs/bxuekTCiSCI/s400/06-add_project_output.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484716088376627218" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;7. Make sure the web application in the current solution is selected, then select Primary Output and Content files. This will add the binaries and necessary files into the msi for installation.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jRUlOncToWc/TB2gaj7wp_I/AAAAAAAAAD0/Wd3XqD4RQ2A/s1600/07-add_project_output.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 351px; height: 400px;" src="http://2.bp.blogspot.com/_jRUlOncToWc/TB2gaj7wp_I/AAAAAAAAAD0/Wd3XqD4RQ2A/s400/07-add_project_output.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484716299390068722" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;8. Right click in the Web Setup project and select Add -&gt; Files. Add the three environment specific web.config file into the setup project.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jRUlOncToWc/TB2gik3ehkI/AAAAAAAAAD8/aVxENUw294M/s1600/08-add_env_webconfig.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 303px; height: 245px;" src="http://4.bp.blogspot.com/_jRUlOncToWc/TB2gik3ehkI/AAAAAAAAAD8/aVxENUw294M/s400/08-add_env_webconfig.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484716437079492162" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now we will begin the steps to add a new dialog to our installer. This dialog will enable user to choose which environment he want to install and the installer will deploy the appropriate web.config file to the installed folder.&lt;br /&gt;&lt;br /&gt;9. Make sure the Web Setup Project is selected. In the visual studio menu, go to View -&gt; Editor -&gt; User Interface. You will now see the list of dialogs which will be presented during the installation time.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jRUlOncToWc/TB2jhvHcMkI/AAAAAAAAAEE/16FQDV731_g/s1600/09-add_ui.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 143px;" src="http://2.bp.blogspot.com/_jRUlOncToWc/TB2jhvHcMkI/AAAAAAAAAEE/16FQDV731_g/s400/09-add_ui.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484719721185817154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;10. Right click on the Start node and select Add Dialog.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jRUlOncToWc/TB2jor8b_CI/AAAAAAAAAEM/Jv9WVWCeSoc/s1600/10-add_dlg_menu.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 238px; height: 161px;" src="http://1.bp.blogspot.com/_jRUlOncToWc/TB2jor8b_CI/AAAAAAAAAEM/Jv9WVWCeSoc/s400/10-add_dlg_menu.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484719840593443874" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;11. Select the Radio Buttons (3 buttons) dialog&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_jRUlOncToWc/TB2j0-_wiTI/AAAAAAAAAEU/0tHo91xrYRo/s1600/11-add_dlg.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 211px;" src="http://3.bp.blogspot.com/_jRUlOncToWc/TB2j0-_wiTI/AAAAAAAAAEU/0tHo91xrYRo/s400/11-add_dlg.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484720051866077490" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;12. Right click on the new dialog you just added and select Move Up. This is to re-order the sequence of dialog presentation during installation time.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jRUlOncToWc/TB2kTQHkrGI/AAAAAAAAAEc/wO4x9tbZzsw/s1600/12-move_up.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 326px; height: 180px;" src="http://1.bp.blogspot.com/_jRUlOncToWc/TB2kTQHkrGI/AAAAAAAAAEc/wO4x9tbZzsw/s400/12-move_up.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484720571858332770" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The dialog sequence should look like this after you complete the step.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jRUlOncToWc/TB2kbcktGWI/AAAAAAAAAEk/vKVWxPINa94/s1600/12b-move_up.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 223px; height: 118px;" src="http://2.bp.blogspot.com/_jRUlOncToWc/TB2kbcktGWI/AAAAAAAAAEk/vKVWxPINa94/s400/12b-move_up.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484720712640698722" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;13. Select the Radio Button dialog, and in the property window, modify the property value to match the following:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_jRUlOncToWc/TB2zX2xo1sI/AAAAAAAAAFk/yJt6xIF8e3g/s1600/13-configure_dialog.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 312px; height: 293px;" src="http://3.bp.blogspot.com/_jRUlOncToWc/TB2zX2xo1sI/AAAAAAAAAFk/yJt6xIF8e3g/s400/13-configure_dialog.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484737143629207234" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The value of the ButtonProperty is the name which will be used for lookup later. The value you specified for ButtonProperty is case sensitive. The ButtonValue is the value which will be set into the lookup name specified by te ButtonProperty. For example, if you select SIT, "2" will be assigned to ENVIRONMENT.&lt;br /&gt;&lt;br /&gt;14. Now select the web.config_dev in the Web Setup project. In the property window, set the Condition and target name to match the following:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_jRUlOncToWc/TB2psnmd12I/AAAAAAAAAE0/Vv6kM7J3UT8/s1600/14-set_condition.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 250px; height: 400px;" src="http://3.bp.blogspot.com/_jRUlOncToWc/TB2psnmd12I/AAAAAAAAAE0/Vv6kM7J3UT8/s400/14-set_condition.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484726505216792418" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Repeat the same for web.config_sit (set the condition to ENVIRONMENT="2") and web.config_prod  (set the condition to ENVIRONMENT="3") &lt;br /&gt;If you specify a condition, the file will only be install if the condition is evaluated to true. The value for ENVIRONMENT is assigned in the Radion Button dialog depend on which radio button you select. Remember "ENVIRONMENT" is case sensitve. It has to match the ButtonProperty value which you specified in the Radio Button dialog.&lt;br /&gt;The TargetName is the actual name for the file when it is copied into the installed folder. In this case, we want to rename it to web.config &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;15. Next, we want to exclude the original web.config file from the web application project. The final web.config will be copied from either one of three environment specific web.confg file. In the Web Setup project, right click on the Content Files, select Exclude Filter.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jRUlOncToWc/TB2rdy_qx1I/AAAAAAAAAE8/MArnxe-gt04/s1600/15-select-exclude_filter.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 308px; height: 306px;" src="http://1.bp.blogspot.com/_jRUlOncToWc/TB2rdy_qx1I/AAAAAAAAAE8/MArnxe-gt04/s400/15-select-exclude_filter.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484728449600505682" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Add web.config to the filter dialog and click OK.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jRUlOncToWc/TB2rk9L-xXI/AAAAAAAAAFE/Jy7GMQtwW4g/s1600/16-add_filter.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 204px;" src="http://1.bp.blogspot.com/_jRUlOncToWc/TB2rk9L-xXI/AAAAAAAAAFE/Jy7GMQtwW4g/s400/16-add_filter.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484728572595586418" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You can now build the installer and run the MSI to install your web application. Remember to run the MSI as administrator if you are in Vista and above.&lt;br /&gt;&lt;br /&gt;You will see the installer wizard dialog as following:&lt;br /&gt;This is the standard dialog for web appliction.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jRUlOncToWc/TB2s4H_AilI/AAAAAAAAAFM/myHZytNMzGk/s1600/17-install_address.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 326px;" src="http://4.bp.blogspot.com/_jRUlOncToWc/TB2s4H_AilI/AAAAAAAAAFM/myHZytNMzGk/s400/17-install_address.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484730001423108690" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is the dialog which we add to allow user to choose the installation environment.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jRUlOncToWc/TB2tAUvkBoI/AAAAAAAAAFU/kAWzCmJYpSE/s1600/17b-install_env.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 259px;" src="http://1.bp.blogspot.com/_jRUlOncToWc/TB2tAUvkBoI/AAAAAAAAAFU/kAWzCmJYpSE/s400/17b-install_env.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484730142286939778" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;After the installation complete, you can open the web.config to verify the correct file for that environment has been installed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-8984392420788139926?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/8984392420788139926/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=8984392420788139926' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/8984392420788139926'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/8984392420788139926'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2010/06/creating-web-setup-project-for-aspnet.html' title='Creating a Web Setup Project for asp.net Application Using Visual Studio'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_jRUlOncToWc/TB2X6rLvkgI/AAAAAAAAADE/9LA9D0NnS_4/s72-c/01-create_web_app.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-787739333228826652</id><published>2010-06-20T11:58:00.003+08:00</published><updated>2010-06-20T12:11:40.435+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><title type='text'>Encoding XML Special Characters</title><content type='html'>To encode string which has XML special characters so that it can be inserted as valid text into xml node, you can use the following API in System.Security namespace.&lt;br /&gt;&lt;pre style="border:solid 1px"&gt;&lt;br /&gt;string s = System.Security.SecurityElement.Escape(&amp;quot;&amp;lt;&amp;gt;&amp;amp;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will produce the following output:&lt;br /&gt;&lt;pre style="border:solid 1px"&gt;&lt;br /&gt;&amp;amp;lt;&amp;amp;gt;&amp;amp;amp;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-787739333228826652?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/787739333228826652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=787739333228826652' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/787739333228826652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/787739333228826652'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2010/06/encoding-xml-special-characters.html' title='Encoding XML Special Characters'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-179056220115000676</id><published>2010-06-20T11:41:00.002+08:00</published><updated>2010-06-20T11:47:58.801+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='web service'/><title type='text'>How to XML serialize simple type as different element name for Generic Collection Type Argument</title><content type='html'>For web service method's parameter which is a generic collection with simple type as the type argument, the type name will be used as the XML element name in the array child node by default.&lt;br /&gt;&lt;br /&gt;Example, if below is your web service method&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[WebMethod]&lt;br /&gt;public string DoWork1(List&amp;lt;string&amp;gt; partNames)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The soap message will looks like the following:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jRUlOncToWc/TB2PC035PoI/AAAAAAAAAC0/zTeNWdhFogg/s1600/standard_element_name.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 387px; height: 285px;" src="http://4.bp.blogspot.com/_jRUlOncToWc/TB2PC035PoI/AAAAAAAAAC0/zTeNWdhFogg/s400/standard_element_name.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484697199922724482" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;However, you can change the XML element name by specifying a &lt;b&gt;XmlArrayItem&lt;/b&gt; attribute to the method's parameter&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[WebMethod]&lt;br /&gt;public string DoWork2([XmlArrayItem(ElementName = &amp;quot;blah&amp;quot;)]List&amp;lt;string&amp;gt; partNames)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jRUlOncToWc/TB2PT4B-YMI/AAAAAAAAAC8/cMlxZ-Us_F0/s1600/custom_element_name.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 373px; height: 284px;" src="http://1.bp.blogspot.com/_jRUlOncToWc/TB2PT4B-YMI/AAAAAAAAAC8/cMlxZ-Us_F0/s400/custom_element_name.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5484697492828086466" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-179056220115000676?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/179056220115000676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=179056220115000676' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/179056220115000676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/179056220115000676'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2010/06/how-to-xml-serialize-simple-type-as.html' title='How to XML serialize simple type as different element name for Generic Collection Type Argument'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_jRUlOncToWc/TB2PC035PoI/AAAAAAAAAC0/zTeNWdhFogg/s72-c/standard_element_name.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-324909391242308299</id><published>2010-03-10T17:57:00.004+08:00</published><updated>2010-03-10T18:08:19.625+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='command line'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Server 2008'/><title type='text'>Finding files in your drive using command prompt</title><content type='html'>There is a command line called &lt;b&gt;where&lt;/b&gt; for finding files in your drive:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jRUlOncToWc/S5dts0sIdaI/AAAAAAAAACs/0IQS23BJ2uI/s1600-h/where_cmd.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand; " src="http://1.bp.blogspot.com/_jRUlOncToWc/S5dts0sIdaI/AAAAAAAAACs/0IQS23BJ2uI/s400/where_cmd.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5446942891153323426" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;where /R . gacutil&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The command above find the location of gacutil recursively(/R) starting from the current directory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-324909391242308299?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/324909391242308299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=324909391242308299' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/324909391242308299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/324909391242308299'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2010/03/finding-files-in-your-drive-using.html' title='Finding files in your drive using command prompt'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_jRUlOncToWc/S5dts0sIdaI/AAAAAAAAACs/0IQS23BJ2uI/s72-c/where_cmd.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-5814600183598814767</id><published>2009-11-17T18:55:00.000+08:00</published><updated>2009-11-17T18:57:09.308+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>Quick (and dirty) way of finding impact of field changes</title><content type='html'>If you are going to change a database table field and want to know what stored proc or UDF will be affected, you can use the following query as a quick and dirty way to find out which stored proc or UDF is using that field.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SELECT routine_name, routine_definition&lt;br /&gt;FROM INFORMATION_SCHEMA.routines&lt;br /&gt;WHERE ROUTINE_DEFINITION LIKE '%TextToSearch%'&lt;br /&gt;ORDER BY last_altered DESC&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-5814600183598814767?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/5814600183598814767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=5814600183598814767' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/5814600183598814767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/5814600183598814767'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2009/11/quick-and-dirty-way-of-finding-impact.html' title='Quick (and dirty) way of finding impact of field changes'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-7236992030440473837</id><published>2008-12-02T22:04:00.003+08:00</published><updated>2008-12-02T22:13:51.328+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Service'/><title type='text'>Extra blank page when Save to PDF from SQL Reporting Service</title><content type='html'>When you save a report as PDF from Sql Reporting Services, you might see an extra blank page in between the pages in the report. This is due to the actual print out size exceed the page size that is specified. &lt;br /&gt;&lt;br /&gt;For example, you specify your report size to be width (11 in) x height (8.5 in) which is a A4 size. However in the body of the report, you might have specify (intentionally or unintentionally) the size to be larger than that. When you save the report to PDF, you will see a blank page because the report size actually run over the page size.&lt;br /&gt;&lt;br /&gt;To solve this problem, make sure you check the Size and Margin property of both the Report and Body (you can access this from the properties window).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-7236992030440473837?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/7236992030440473837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=7236992030440473837' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/7236992030440473837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/7236992030440473837'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/12/extra-blank-page-when-save-to-pdf-from.html' title='Extra blank page when Save to PDF from SQL Reporting Service'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-1956787524541654566</id><published>2008-12-02T22:01:00.000+08:00</published><updated>2008-12-02T22:02:06.069+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Basic'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Visual Basic Divide operator</title><content type='html'>For non profressional Visual Basic developer it might not be apparent that VB has two divide operator.&lt;br /&gt;&lt;br /&gt;The first divide operator which is more commonly used is '/'. This operator will return the result with decimal&lt;br /&gt;if the number being divided (also call &lt;a href="http://en.wikipedia.org/wiki/Division_(mathematics)" target="_blank"&gt;dividend&lt;/a&gt;)&lt;br /&gt;cannot be fully divide by the divisor.&lt;br /&gt;&lt;br /&gt;The second divide operator '\', which is also called integer division will always return the result (also call &lt;a href="http://en.wikipedia.org/wiki/Quotient" target="_blank"&gt;Quotient&lt;/a&gt;) in integer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-1956787524541654566?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/1956787524541654566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=1956787524541654566' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1956787524541654566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1956787524541654566'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/12/visual-basic-divide-operator.html' title='Visual Basic Divide operator'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-835999548743216336</id><published>2008-08-17T23:00:00.001+08:00</published><updated>2008-08-17T23:03:02.118+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='management'/><title type='text'>Essence of Growing the Company</title><content type='html'>As company start to mature and grow in business or there is a sudden boom of business opportunity, they also start to hire aggressively. This is a natural progress. However, sometime this transition has a negative effect on the company and to the employees if the growth is not managed properly.&lt;br /&gt;&lt;br /&gt;First, when the number of employees increases, the management and reporting structure also need to be changed. When the company has only 15 employees, everyone can easily get into each other and know what is going on in the company. The CEO can easily talk to any employees because they sit closer in the smaller office space and it is easy to address 10 to 15 peoples. The CEO can almost oversee everything in the company. However, when the company grow to 30 or 40 peoples, the situation start to change. The CEO and senior management will spend more time on business matters and less time in internal company affairs. The office space will also expand and possibly has remote office. This means that management has less time to understand employees’ affairs and improve the company for their employees. At this stage, HR play an important role to serve as the voice between the employees and the management. An important part of the HR job is to ensure the employees satisfaction is always remain high and play an proactive role in driving the company and employees improvement. &lt;br /&gt;&lt;br /&gt;Second, one of the tough changes when a small company transition into a more mature middle size company is the reluctance of the CEO or founder of the company to relinquish management control to the rest of the management team. This is a difficult change for a lot founders as they still see the company as "their own company" rather than develop an objective and separate view between their ownership of the company and what is good for the long term future of the company.&lt;br /&gt;&lt;br /&gt;Third, job function still start to specialized and new reporting hierarchy is introduced. This means employees will become more distanced from each other. Managers play a vital role in understanding the company direction and hold the team tight by delivering the message to their subordinate and drive everyone towards the same direction.&lt;br /&gt;&lt;br /&gt;Forth, the culture and style of working will also undergo changes. As the business and employee size has grown,  company might start to put in new company governance policy because management need a more structured way to operate the team in a more self-sustained way. The company may also need a new set of core values in order for them to succeed in the next stage.&lt;br /&gt;&lt;br /&gt;It is unavoidable that in this stage, the company and the employees will go through the growing pain. Some employees will feel resistant to the change, some employees will feel that company  is now trying to restrict their freedom, some employees just have no clue why the company is doing this and that. Just like a kid who transition into a teenager or a teenager who transition in an adult.  During this transition, some people who had not done well in their earlier life will find their direction and excel in it. Some will lost their direction or get influenced by some bad friends and goes bad. The growing pain need to be managed well so that it doesn’t goes out of control.&lt;br /&gt; &lt;br /&gt;First of all, the founders need to maintain an objective view of what is good and needed for the company to succeed in their new stage. This includes stepping aside and promoting someone or even hiring someone from outside the company who are more capable to take on their responsibility. By releasing some of their day to day responsibilities, the founders can have more time to look at the company and business in a broader view, set new direction and prepare the company for their next life. This is same as if you are already holding a handful of things in your hand, you cannot grab new things unless you release what you are currently holding.&lt;br /&gt;&lt;br /&gt;Second, employees need to be addressed so that they understand what is happening within the company, the rationale behind the series of changes that is taking place in the company, what is expected from them and how they can contribute to the continuous success of the company. It is important for all employees to understand the business landscape so that they appreciate their role better not just in term of the niche view of the organization chart, but also from the perspective of the business and how they can make a difference and impact. It also help employee to understand what they need and develop new mindset in order to do better and adapt to the new changes and culture in the company.&lt;br /&gt;&lt;br /&gt;Third, employees need to be prepared for the change. This include develop new and nurture leadership within the company long before changes start to take place. Employees need to be trained, guided and empowered   to make decision and take on additional responsibility beyond what is expected from them. Founders and managers need to understand that in order for them to do something bigger, they need someone who can replace them and do their job so that they can move up higher. Leadership is about replicating more leaders, not just how to do a new job.  This include training the new born leaders to understand business landscape, how to make tradeoff and decision, how to lead people, how to develop new leadership, how to be caring (if you don’t care enough, how can you make change), develop new skill sets and so on. The skill sets and mentality needed to be a manager and leader is different from those of regular team player. Leadership takes time to nurture. It is not something that can happen overnight.&lt;br /&gt;&lt;br /&gt;Forth, don’t hire too aggressively. Whether you are hiring people who are experience or inexperience, these new employees will go through a learning curve and adapt to a new working culture. You need to have enough leadership within the company to guide them to a productive stage.  Of course you should only hire people who can swim on their own, but it doesn’t mean you can neglect them in a corner just busy with their own work.  Leadership and guidance is still needed to align them to the company’s culture and core values and their progress need to be monitored until they are truly productive in the company. Make sure your existing employees are prepared to guide new peoples before you start to employ in big ways.&lt;br /&gt;&lt;br /&gt;Fifth, before you even start expanding the number of employees in the company, make sure the existing employees are happy. There is no point if on one hand the company is hiring new employees, but on the other hand is losing good employees. There are usually three reasons why an employee leaves the company:&lt;br /&gt;&lt;UL&gt;&lt;br /&gt;&lt;LI&gt;First, their remuneration is not up to the market standard. In simple words, they are under paid. If this is the case, it is a simple fix.&lt;br /&gt;&lt;LI&gt;Second, bad manager. Employees  leave the company because they cannot get along with their manager or the manager is simply not capable.  This is a much harder problem to identify and fix.  One way to spot this is to allow employees to appraise their manager during the appraisal and review period.&lt;br /&gt;&lt;LI&gt;Third, employees feel that they are stagnant in the company. This usually happen in company where no new business is developed, the employee is put in the same position doing the same old thing for a long time or the company has not prepare these people to move up in their careers.&lt;br /&gt;&lt;/UL&gt;&lt;br /&gt;&lt;br /&gt;I believe leadership and core values are more important for the long term success of the company than the employees’ past experience and skill sets. Experience and skill sets can be rendered useless when business nature and job role are changed. Leadership and core values are what keep people moving in the same direction.&lt;br /&gt;&lt;br /&gt;I have seen some companies which have been staying in the same size for a long period of time due to lacks of leadership within the company.  The company is mainly drive by the same person over many years and how much one or two person can accomplish?&lt;br /&gt;&lt;br /&gt;I have also seen companies that outgrowth themselves. They hire so fast and so aggressively that they have no way to manage the situation and things simply goes out of control. This phenomenon is especially obvious during the dot com boom days.  It also happen in companies that get external funding. When some companies got funded, they just simply hire new employees just for the sake of expansion.&lt;br /&gt;&lt;br /&gt;I believe that the essence of growing a company is that management needs to instill leadership from day one of the company life and prepare their employees to growth with the company and take on new role when the company expands. This has to happen before the company actually grow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-835999548743216336?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/835999548743216336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=835999548743216336' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/835999548743216336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/835999548743216336'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/08/essence-of-growing-company.html' title='Essence of Growing the Company'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-1668560285045360818</id><published>2008-08-02T17:22:00.001+08:00</published><updated>2008-08-02T17:24:44.247+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><title type='text'>DataBoy v1.0.6.2 is Out!</title><content type='html'>DataBoy v1.0.6.2 is released!&lt;br /&gt;&lt;br /&gt;New features include:&lt;br /&gt;&lt;UL&gt;&lt;br /&gt;&lt;LI&gt;Ctrl + Shift + (Left/Right cursor) short cut key to switch between Result and Message tab.&lt;br /&gt;&lt;LI&gt;Connection time out setting for SQL Server connection.&lt;br /&gt;&lt;LI&gt;Open and Save connection as Connection Group to a file.&lt;br /&gt;&lt;LI&gt;Remember last session.&lt;br /&gt;&lt;LI&gt;Option to persist login info. Select Persist Login Info if you want database user name and password to be saved with the connection when you save a connection group.&lt;br /&gt;&lt;LI&gt;Table column ordering in the data explorer panel tree view is now according to the sequence in the meta data.&lt;br /&gt;&lt;/UL&gt;&lt;br /&gt;&lt;br /&gt;You can download Databoy from Codeplex : &lt;a href="http://www.codeplex.com/databoy" target="_blank"&gt;Databoy&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-1668560285045360818?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/1668560285045360818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=1668560285045360818' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1668560285045360818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1668560285045360818'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/08/databoy-v1062-is-out.html' title='DataBoy v1.0.6.2 is Out!'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-1222886949398096195</id><published>2008-07-30T11:16:00.002+08:00</published><updated>2008-07-30T11:25:29.723+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='EPM'/><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>Project Server 2007 : Queue system could not start</title><content type='html'>If your project server 2007 deployment use a different account for the farm service and Shared Service Provider (SSP), you might face some problem with the Project Server Queue Service.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;By default, the Project Server Queue Service run under the account that is used for the farm service. If your queue job cannot be processed and you see the following message in Event Viewer :&lt;br /&gt;&lt;br /&gt;Queue system could not start. SSP: {guid}.&lt;br /&gt;&lt;br /&gt;Try change the Project Server Queue Service account to the one that is used to run the Shared Service Provider.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Go to Services and change the &lt;i&gt;Microsoft Office Project Server Queue Service&lt;/i&gt; service account to the account that is used to run the SSP.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-1222886949398096195?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/1222886949398096195/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=1222886949398096195' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1222886949398096195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1222886949398096195'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/07/project-server-2007-queue-system-could.html' title='Project Server 2007 : Queue system could not start'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-7315649953461119401</id><published>2008-07-23T16:55:00.004+08:00</published><updated>2008-12-02T22:18:12.303+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Service'/><title type='text'>Licensing Requirement to Install Reporting Service on separate server</title><content type='html'>I was asked if the SQL Server Reporting Service is installed in a separate server from where the SQL Server database engine is installed, does it need another SQL Server license?&lt;br /&gt;&lt;br /&gt;Although I am not a licensing expert (and not many people seem to be able to understand Microsoft Licensing scheme), but I can confidently say Yes to the question above.&lt;br /&gt;&lt;br /&gt;The answer lies in the following document:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cid-87f95f1b5b21b01e.skydrive.live.com/self.aspx/Licensing%20Briefs/Licensing%20Briefs%20Current/SQL%20Server%202005%20Licensing%20%7C5long%20version%7C6.doc" target="_blank"&gt;Licensing Doc&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In the above scenario, you need two SQL Server license.&lt;br /&gt;&lt;br /&gt;I hope Microsoft can be more open and clear in communicating licensing issue and requirement in the future. It will be good if they can include some of the common deployment scenario for their software together with the licensing requirement in Technet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-7315649953461119401?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/7315649953461119401/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=7315649953461119401' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/7315649953461119401'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/7315649953461119401'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/07/licensing-requirement-to-install.html' title='Licensing Requirement to Install Reporting Service on separate server'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-4654067296168308292</id><published>2008-07-15T17:35:00.002+08:00</published><updated>2008-07-15T17:36:49.629+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows Server 2008'/><title type='text'>Disable Windows Server Shutdown Reason</title><content type='html'>Windows Server 2003 and 2008 require you to specify a reason everytime you shutdown your server. If you are using Windows Server as your workstation like me, you may find this a bit annoying. Luckily, There is a way to disable it.&lt;br /&gt;&lt;br /&gt;To disable the shut down reason, &lt;br /&gt;1) run gpedit.msc. This will start the Local Group Policy Editor.&lt;br /&gt;2) Go to Computer Configuration -&gt; Administrative Templates -&gt; System.&lt;br /&gt;3) Look for 'Display Shutdown Event Tracker'. Then set it to Disabled&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp3.blogger.com/_jRUlOncToWc/SHxvi4wGAmI/AAAAAAAAAB4/5efq8TCI2XM/s1600-h/shutdown_event_tracker.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_jRUlOncToWc/SHxvi4wGAmI/AAAAAAAAAB4/5efq8TCI2XM/s320/shutdown_event_tracker.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5223172312983274082" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-4654067296168308292?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/4654067296168308292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=4654067296168308292' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4654067296168308292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4654067296168308292'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/07/disable-windows-server-shutdown-reason.html' title='Disable Windows Server Shutdown Reason'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_jRUlOncToWc/SHxvi4wGAmI/AAAAAAAAAB4/5efq8TCI2XM/s72-c/shutdown_event_tracker.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-1467498063213038692</id><published>2008-07-06T10:42:00.003+08:00</published><updated>2008-07-06T11:00:43.684+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='EPM'/><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>Project 2007 error : "Could not retrieve Enteprise Global Template"</title><content type='html'>When I try to connect the Project 2007 to Project Server for one of my user few days ago, I got an error from MS Project: "Could not retrieve Enteprise Global Template".&lt;br /&gt;&lt;br /&gt;After some googling, Google for "&lt;a href="http://www.google.com.my/search?hl=en&amp;q=%22could+not+retrieve+Enterprise+Global+Template%22&amp;meta=" target="_blank"&gt;Could not retrieve Enteprise Global Template&lt;/a&gt;", I cann't find a sympton and solution that match my situation.&lt;br /&gt;&lt;br /&gt;After some diagnosis and reproduction, I manage to isolate the problem into a case that this error only happen for that user on his computer. I recall that this user has just migrated his profile when he join his computer from workgroup into domain.&lt;br /&gt;&lt;br /&gt;It turn out that after the profile migration, his MS Project cache location is pointing to a location that he currently do not have permission to access anymore. This cause MS Project to fail everytime when it need to retrieve the Enterprise Global Template from the cache. &lt;br /&gt;&lt;br /&gt;This setting is stored in registry. The solution is to remove the setting from the registry and restart MS Project. Remove the following registry key: HKCU\Software\Microsoft\Office\12.0\MS Project\Settings:CacheLocation&lt;br /&gt;&lt;br /&gt;,then restart MS Project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-1467498063213038692?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/1467498063213038692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=1467498063213038692' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1467498063213038692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1467498063213038692'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/07/project-2007-error-could-not-retrieve.html' title='Project 2007 error : &quot;Could not retrieve Enteprise Global Template&quot;'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-3227353198651294209</id><published>2008-06-21T13:21:00.002+08:00</published><updated>2008-06-21T13:54:11.520+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>Planning for DataBoy vNext</title><content type='html'>I am currently planning and designing some new feature for the next version of DataBoy. I have receive some feedback for some enhancement that people would like to see. &lt;br /&gt;&lt;br /&gt;This new release will be considered as minor update as there will be no new major feature that require significant design rework. All the new things are just enhancement that make DataBoy more usable.&lt;br /&gt;&lt;br /&gt;Some of the enhancement that is planned includes:&lt;br /&gt;- Short cut key to switch data and message tab.&lt;br /&gt;- Connection time out in the Add Connection dialog (only for SQL Server).&lt;br /&gt;- Set the cursor focus back to sql editor after a query is runned.&lt;br /&gt;- Order column in data explorer tree view according to sequence in meta data.&lt;br /&gt;- Persist database connection.&lt;br /&gt;&lt;br /&gt;My target is to release in four weeks from now.&lt;br /&gt;&lt;br /&gt;I would also like to re-iterate that the objective of DataBoy is to provide a simple tool to query database. It is not meant to be a database management tool. As such, all new feature request will be evaluated and design along this line.&lt;br /&gt;&lt;br /&gt;The two main scenarios in which DataBoy is designed to support are:&lt;br /&gt;a) Application support personnel/Developer can easily copy DataBoy into the end user computer (where there is no dev tool) or a computer where there is no SQl management tool  installed and start querying the database for application diagnosis.&lt;br /&gt;&lt;br /&gt;b) To enable application development with SQL CE much easier. At the time DataBoy was developed, the toolset for working with SQL CE v3.5 was very limited as SQL Server 2008 was not yet release and fully supported.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Having said that, I still welcome all feedbacks and enhancement request.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-3227353198651294209?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/3227353198651294209/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=3227353198651294209' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/3227353198651294209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/3227353198651294209'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/06/planning-for-databoy-vnext.html' title='Planning for DataBoy vNext'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-2570958601706187217</id><published>2008-05-20T15:30:00.003+08:00</published><updated>2008-05-20T15:31:27.683+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Server 2008'/><title type='text'>Installing SQL Server 2005 and Reporting Service on Windows Server 2008</title><content type='html'>Some helpful link to install SQL Server 2005 and Reporting Service (especially) on Windows Server 2008&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.microsoft.com/kb/920201/en-us" target="_blank"&gt;You receive a warning message on the System Configuration Check page of the SQL Server 2005 Setup program on a computer that is running Windows Vista or a Server Core installation of Windows Server 2008&lt;/a&gt;&lt;br&gt;&lt;br /&gt;&lt;a href="http://support.microsoft.com/kb/938245/" target="_blank"&gt;How to install and how to configure SQL Server 2005 Reporting Services on a computer that is running Windows Server 2008&lt;/a&gt;&lt;br&gt;&lt;br /&gt;&lt;a href="http://support.microsoft.com/kb/934164" target="_blank"&gt;How to install SQL Server 2005 Reporting Services on a Windows Vista-based computer&lt;/a&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-2570958601706187217?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/2570958601706187217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=2570958601706187217' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/2570958601706187217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/2570958601706187217'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/05/installing-sql-server-2005-and.html' title='Installing SQL Server 2005 and Reporting Service on Windows Server 2008'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-9061691912862697754</id><published>2008-05-20T15:12:00.006+08:00</published><updated>2008-05-20T15:22:12.962+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows Server 2008'/><title type='text'>Changing File Type Association in Windows Server 2008</title><content type='html'>The file type association specify which program are used to open a document by default. In Windows XP and Window Server 2003, this is done by go to &lt;br /&gt;&lt;br /&gt;&lt;i&gt;Tools -&gt; Folder Options&lt;/i&gt; from the Windows Explorer and select the &lt;i&gt;File Type&lt;/i&gt; tab.&lt;br /&gt;&lt;br /&gt;In Windows Server 2008, the UI has changed quite abit. Instead, to accomplish the same thing, you have to go to &lt;i&gt;Control Panel -&gt; Default Programs&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp1.blogger.com/_jRUlOncToWc/SDJ7GMQVcDI/AAAAAAAAABw/S2MdpZ-Rhe8/s1600-h/change_default_association.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_jRUlOncToWc/SDJ7GMQVcDI/AAAAAAAAABw/S2MdpZ-Rhe8/s320/change_default_association.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5202355865865515058" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-9061691912862697754?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/9061691912862697754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=9061691912862697754' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/9061691912862697754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/9061691912862697754'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/05/changing-file-type-association-in.html' title='Changing File Type Association in Windows Server 2008'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_jRUlOncToWc/SDJ7GMQVcDI/AAAAAAAAABw/S2MdpZ-Rhe8/s72-c/change_default_association.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-2988017223571065697</id><published>2008-05-20T14:47:00.005+08:00</published><updated>2008-05-20T14:58:21.788+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows Server 2008'/><title type='text'>Enabling Wireless on Windows Server 2008</title><content type='html'>After installing Windows Server 2008, it took me quite a while to figure out where things are located.&lt;br /&gt;&lt;br /&gt;One of my first learning curve is finding out how to enable wireless in Windows Server 2008.&lt;br /&gt;&lt;br /&gt;First, make sure the wireless adapter is working. To check this, go to Network and Sharing Center, click on the &lt;i&gt;Manage network connections&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp2.blogger.com/_jRUlOncToWc/SDJ1gcQVcBI/AAAAAAAAABg/gqd0Vk1auwI/s1600-h/networking.jpg"&gt;&lt;br /&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_jRUlOncToWc/SDJ1gcQVcBI/AAAAAAAAABg/gqd0Vk1auwI/s320/networking.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5202349719767314450" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Next, goto &lt;i&gt;Server Manager -&gt; Features&lt;/i&gt; to add the Wireless feature.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp0.blogger.com/_jRUlOncToWc/SDJ128QVcCI/AAAAAAAAABo/KAnZ1spcdHI/s1600-h/enable_wireless.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_jRUlOncToWc/SDJ128QVcCI/AAAAAAAAABo/KAnZ1spcdHI/s320/enable_wireless.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5202350106314371106" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then, you can configure your wireless to connect to the available wireless network.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-2988017223571065697?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/2988017223571065697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=2988017223571065697' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/2988017223571065697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/2988017223571065697'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/05/enabling-wireless-on-windows-server.html' title='Enabling Wireless on Windows Server 2008'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_jRUlOncToWc/SDJ1gcQVcBI/AAAAAAAAABg/gqd0Vk1auwI/s72-c/networking.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-8428698432833945076</id><published>2008-04-26T18:15:00.001+08:00</published><updated>2008-07-06T11:14:20.231+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Parallelism, Concurrency and the free lunch</title><content type='html'>For anybody who is looking for ways of how to take advantage of the CPU capability to make their program run faster, I would suggest to look at the &lt;a href="http://msdn2.microsoft.com/en-us/concurrency/default.aspx" target="_blank"&gt;Parallel Framework Extension&lt;/a&gt; and download the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e848dc1d-5be3-4941-8705-024bc7f180ba&amp;amp;DisplayLang=en" target="_blank"&gt;PFX CTP&lt;/a&gt; to try it out.&lt;br /&gt;&lt;br /&gt;I was just optimizing my program. On my dual core machine, the improved version of my program which use PFX give me an approximate of 18% performance improvement over the original program which use a conventional foreach loop. As my data set increase, the gain is up to about 35%.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why this is a big deal?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;As the silicon has reach its physics limit of getting more into the CPU chip, we cannot depend on &lt;a href="http://en.wikipedia.org/wiki/Moore_Law" target="_blank"&gt;Moore’s law&lt;/a&gt; to take care of performance for us anymore. &lt;a href="http://www.gotw.ca/publications/concurrency-ddj.htm" target="_blank"&gt;The free lunch is pretty much over&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Instead, we can see emerging trend in parallelism and concurrency. People today are talking about multi core processors and how to make program run faster by utilizing all the cores they have in the computer; &lt;a href="http://en.wikipedia.org/wiki/Functional_programming" target="_blank"&gt;functional programming language&lt;/a&gt; is getting &lt;a href="http://www.defmacro.org/ramblings/fp.html" target="_blank"&gt;more attention&lt;/a&gt;; functional programming elements start to incorporated into mainstream imperative language (example is Linq); &lt;a href="http://en.wikipedia.org/wiki/Software_transactional_memory" target="_blank"&gt;Software Transactional Memory&lt;/a&gt; is also getting more research effort.&lt;br /&gt;&lt;br /&gt;I bet that concurrency is going to be one of the important topics in the next wave of programming paradigm.&lt;br /&gt;&lt;br /&gt;Having say that, I dont mean concurrency is the ultimate to all problems. Concurrency is a tough subject and hard to get it right. You have to weight whether the overhead of locking is worth the benefits; You have to understand the side effects of state changes; You have to find a way to handle exception and etc. Concurrency is mean to be a way of tapping into the spare processing capacity, not a way to make slow code fast. You still have to understand where the bottleneck is in your code before you decide to settle on making things more concurrent. Use it with care.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-8428698432833945076?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/8428698432833945076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=8428698432833945076' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/8428698432833945076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/8428698432833945076'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/04/parallelism-concurrency-and-free-lunch.html' title='Parallelism, Concurrency and the free lunch'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-4642213804871865277</id><published>2008-04-09T23:58:00.001+08:00</published><updated>2008-04-10T00:02:04.667+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>DataBoy 1.0 released</title><content type='html'>I have just publish DataBoy version 1 in &lt;a href="http://www.codeplex.com" target="_blank"&gt;codeplex.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DataBoy is a small footprint and portable tool to perform simple query against SQL CE and SQL Server. It is used as an alternative query tool for SQL Management console.&lt;br /&gt;&lt;br /&gt;The download link is here : &lt;a href="http://www.codeplex.com/databoy" target="_blank"&gt;DataBoy&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-4642213804871865277?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/4642213804871865277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=4642213804871865277' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4642213804871865277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4642213804871865277'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/04/databoy-10-released.html' title='DataBoy 1.0 released'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-6127684674887681684</id><published>2008-04-08T23:05:00.001+08:00</published><updated>2008-04-08T23:30:28.120+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><title type='text'>Thought on WPF</title><content type='html'>I recall that some time I go I was having a conversation with my colleague about WPF. His complaint was that the XAML thing is really complicated, messy and difficult to comprehend. While I am supporting the blue badge camp, there is in fact some truth to his statements and this lead to an interesting discussion and thought.&lt;br /&gt;&lt;br /&gt;WPF and XAML is kind of a revolutionary, and it requires a new way of thinking and accepting it. Although XAML should feel natural to developer and designer who are familiar to HTML, the expressiveness of XAML is extended way beyond of what we can used to imagine. Just like HTML, XAML is very good and simple in specifying the UI layout and content without needing to think through the object model. However, as the UI get more complex and the XAML growth, it become more difficult to manage a large chunk of XAML.&lt;br /&gt;&lt;br /&gt;Second, the tool support for WPF is still pretty weak. Visual Studio 2008 and Expression Blend each has a WPF UI designer, but neither are really strong. Visual Studio 2008 are sufficient for creating simple WPF application but is not the right tool for creating complex, fancy and interaction rich application. Expression Blend fill in this gap but the shortcoming is it does not have intelisense support and the XAML editor does not support the same short cut key as in Visual Studio. Add on to this is the performance of the WPF designer in both tool sucks! The debug-ability of XAML application is also very weak. The best thing Visual Studio does now is just to throw an exception in its InitializeComponent() method whenever there is an error in the XAML. It is up to the developer to figure out what went wrong. To be fair, WPF is still a relatively new thing, and we should give the blue badge guy more time to get the tool right. Hopefully it won’t take long for this to happen. &lt;br /&gt;&lt;br /&gt;WPF introduce a lot of new concepts such as property element, markup extension and so on. Developer who are not familiar with XML has even a harder time to understand how XAML is structured (I had a colleague who just managed to figure out what XML namespace is recently). Using markup extension in XAML really takes some time to figure out how it works because of the way it is expressed in attribute value string and the special syntax notation it had.&lt;br /&gt;&lt;br /&gt;Enough rambling about WPF and XAML. XAML does have some good thing that we should praise about. Most notably, The expressiveness of XAML makes certain expression easier to understand than in imperative code. For example, let say I have a button on the form which width I want it to automatically adjust based on a value in a textbox that the user can type in. The most obvious way and simplest to do this is using data binding. Specifying in XAML will look like this :&lt;br /&gt;&lt;br /&gt;&lt;pre style="border:1px solid;"&gt;&amp;lt;WrapPanel&amp;gt;&lt;br /&gt;  &amp;lt;Button x:Name="btnOk" Content="Clickme" &lt;br /&gt;         Width="{Binding Path=Text, ElementName=txtWidth, Mode=Default}" /&amp;gt;&lt;br /&gt;  &amp;lt;TextBox x:Name="txtWidth" Text="120"/&amp;gt;&lt;br /&gt;&amp;lt;/WrapPanel&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To achieve the same effect in C#, the code will look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border:1px solid;"&gt;Binding myBinding = null;&lt;br /&gt;myBinding = new Binding("Text");&lt;br /&gt;myBinding.ElementName = "txtWidth";&lt;br /&gt;btnOk.SetBinding(Button.WidthProperty, myBinding);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or &lt;br /&gt;&lt;pre style="border:1px solid;"&gt;Binding myBinding = null;&lt;br /&gt;myBinding = new Binding("Text");&lt;br /&gt;myBinding.ElementName = "txtWidth";&lt;br /&gt;BindingOperations.SetBinding(btnOk, Button.WidthProperty, myBinding);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Neither of the C# code is any easier to understand than the XAML code. On top of that, it is not easy and obvious to figure out the right API and object model to do it in C# code. When I type btnOk.width in Visual Studio, intellisense show that width property is of type double, thus it seem that  there can be nothing much that can be done about it. So, XAML win in this aspect.&lt;br /&gt;&lt;br /&gt;The XML nature of XAML allow us to visualize better the layout hierrarchy of UI controls. The ability to define resources such as style and templates in XAML right at the appropriate context and being able to specify complex UI controls in the Content property in XAML add on to the clarity and simplicity of the UI definition than doing it at code level. &lt;br /&gt;&lt;br /&gt;WPF and XAML is still weak is some areas especially the tooling support. But nonetheless, this should not hinder us from embracing a new technology. The technology landscape is constantly changing and we should always approach new technology with a new and open mindset.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-6127684674887681684?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/6127684674887681684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=6127684674887681684' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/6127684674887681684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/6127684674887681684'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/04/thought-on-wpf.html' title='Thought on WPF'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-6576363581577137385</id><published>2008-01-14T22:47:00.000+08:00</published><updated>2008-01-15T10:22:01.324+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='visualstudio'/><title type='text'>Code Snippet for WPF Dependency Property</title><content type='html'>I posted a Visual Studio C# code snippet to generate WPF dependency property.&lt;br /&gt;&lt;br /&gt;It can be download at &lt;a href="http://www.codeplex.com/jywpf" target="_blank"&gt;Jonathan's WPF Related Stuff&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-6576363581577137385?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/6576363581577137385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=6576363581577137385' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/6576363581577137385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/6576363581577137385'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/01/code-snippet-for-wpf-dependency.html' title='Code Snippet for WPF Dependency Property'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-8375492994421109157</id><published>2008-01-13T22:36:00.000+08:00</published><updated>2008-01-13T22:46:22.474+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>Hammock Task in MS Project</title><content type='html'>I publish a VBA code that implement a hammock task in MS Project (A useful feature missing from MS Project for many versions).&lt;br /&gt;&lt;br /&gt;It can be download at &lt;a href="http://www.codeplex.com/jymsproject" target="_blank"&gt;Hammock Task in MS Project&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-8375492994421109157?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/8375492994421109157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=8375492994421109157' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/8375492994421109157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/8375492994421109157'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2008/01/hammock-task-in-ms-project.html' title='Hammock Task in MS Project'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-7931588130332798050</id><published>2007-09-02T21:00:00.000+08:00</published><updated>2007-09-02T23:29:37.398+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>Reflection on Generic, Part 3 - Instantiate Generic Type</title><content type='html'>In this post, we will look at how to use reflection to instantiate a generic type.&lt;br /&gt;First, let start with an example of how to do it in the usual way without reflection.&lt;br /&gt;&lt;br /&gt;&lt;pre style="color: #000000; border:1px solid; background-color:white"&gt;&lt;span style="color: #0000FF"&gt;static&lt;/span&gt; &lt;span style="color: #0000FF"&gt;void&lt;/span&gt; Main(&lt;span style="color: #0000FF"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;{    &lt;br /&gt;  List&amp;lt;&lt;span style="color: #0000FF"&gt;string&lt;/span&gt;&amp;gt; list = InstatiateList();    &lt;br /&gt;  list.ForEach(&lt;span style="color: #0000FF"&gt;delegate&lt;/span&gt;(&lt;span style="color: #0000FF"&gt;string&lt;/span&gt; s) { Console.WriteLine(s); });     &lt;br /&gt;  Console.ReadLine();&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000FF"&gt;private&lt;/span&gt; &lt;span style="color: #0000FF"&gt;static&lt;/span&gt; List&amp;lt;&lt;span style="color: #0000FF"&gt;string&lt;/span&gt;&amp;gt; InstatiateList()&lt;br /&gt;{    &lt;br /&gt;  List&amp;lt;&lt;span style="color: #0000FF"&gt;string&lt;/span&gt;&amp;gt; listOfString = &lt;span style="color: #0000FF"&gt;new&lt;/span&gt; List&amp;lt;&lt;span style="color: #0000FF"&gt;string&lt;/span&gt;&amp;gt;();    &lt;br /&gt;  listOfString.Add(&lt;span style="color: #848284"&gt;"AAA"&lt;/span&gt;);    &lt;br /&gt;  listOfString.Add(&lt;span style="color: #848284"&gt;"BBB"&lt;/span&gt;);     &lt;br /&gt;  &lt;span style="color: #0000FF"&gt;return&lt;/span&gt; listOfString;&lt;br /&gt;}&lt;/pre&gt;The above code will print out&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;AAA&lt;br /&gt;BBB&lt;/pre&gt;&lt;br /&gt;Now, lets do it the reflection way.&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;static void Main(string[] args)    &lt;br /&gt;{&lt;br /&gt;    List&amp;lt;string&amp;gt; list = InstatiateListReflectionWay();&lt;br /&gt;    list.ForEach(delegate(string s) { Console.WriteLine(s); });&lt;br /&gt;    Console.ReadLine();&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;private static List&amp;lt;string&amp;gt; InstatiateListReflectionWay()&lt;br /&gt;{&lt;br /&gt;    // Get the metadata for List_Of_T&lt;br /&gt;    Type t = typeof(List&amp;lt;&amp;gt;);&lt;br /&gt;&amp;nbsp;    &lt;br /&gt;    // Make a type definition for List_Of_String&lt;br /&gt;    Type[] typeArg = new Type[1] { typeof(string) };    &lt;br /&gt;    Type listOfStringDef = t.MakeGenericType(typeArg);&lt;br /&gt;&amp;nbsp;    &lt;br /&gt;    // Get the method metadata for Add() method.&lt;br /&gt;    MethodInfo mi = listOfStringDef.GetMethod("Add");&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    // Create an instance of List_Of_String.&lt;br /&gt;    object listOfString = Activator.CreateInstance(listOfStringDef);&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    // Add two element to the list.&lt;br /&gt;    mi.Invoke(listOfString, new object[] { "CCC" });&lt;br /&gt;    mi.Invoke(listOfString, new object[] { "DDD" });&lt;br /&gt;    return (List&amp;lt;string&amp;gt;)listOfString;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above code will print out:&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;CCC&lt;br /&gt;DDD&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Even when you use reflection, the runtime still give you strongly type checking protection against your code. To prove this, insert the following code before the return statement in InstatiateListReflectionWay().&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;mi.Invoke(listOfString, new object[] { 123 });&lt;/pre&gt;&lt;br /&gt;This time, when you run the code again, you will see an exception thrown.&lt;br /&gt;&lt;a href="http://bp1.blogger.com/_jRUlOncToWc/Rtqym4OuFrI/AAAAAAAAABY/2Znyw0eXX40/s1600-h/generic_exception.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_jRUlOncToWc/Rtqym4OuFrI/AAAAAAAAABY/2Znyw0eXX40/s320/generic_exception.JPG" border="0" alt="Exception thrown." id="BLOGGER_PHOTO_ID_5105589508576777906" /&gt;&lt;BR&gt;Exception thrown when insert a number into list_of_string. Click to view in full size.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-7931588130332798050?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/7931588130332798050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=7931588130332798050' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/7931588130332798050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/7931588130332798050'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/09/reflection-on-generic-part-3.html' title='Reflection on Generic, Part 3 - Instantiate Generic Type'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_jRUlOncToWc/Rtqym4OuFrI/AAAAAAAAABY/2Znyw0eXX40/s72-c/generic_exception.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-4622131595745906681</id><published>2007-09-02T19:44:00.000+08:00</published><updated>2007-09-02T21:01:56.558+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>Reflection on Generic, Part 2 - Reflecting Type Parameter</title><content type='html'>In the previous post, you have know how to retrieve type metadata for a generic type. In this post, let's walk through how to retrieve metadata for the type parameter. Let's use the following code as example:&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;public interface IPrint&lt;br /&gt;{&lt;br /&gt;    string Print();&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;public class PrintingDevice&amp;lt;T&amp;gt; where T: class, IPrint, new() &lt;br /&gt;{&lt;br /&gt;    public T Device;&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;public class ValueGenericType&amp;lt;T&amp;gt; where T : struct&lt;br /&gt;{&lt;br /&gt;    public T Value;&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;....&lt;br /&gt;&amp;nbsp;&lt;br /&gt;private static void DumpType(Type t)&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine("Is Generic Type : {0}", t.IsGenericType);&lt;br /&gt;    Console.WriteLine("Type Name : {0}", t.FullName);&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    Type[] genericArguments = t.GetGenericArguments();&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    Console.WriteLine("Number of type parameter : {0}", genericArguments.Length);&lt;br /&gt;    foreach (Type typeArg in genericArguments)&lt;br /&gt;    {&lt;br /&gt;        // Check whether the current type represent a Generic Parameter.&lt;br /&gt;        Console.WriteLine("Is Generic Parameter : {0}", typeArg.IsGenericParameter);&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        // Get the constraint specified for type parameter&lt;br /&gt;        GenericParameterAttributes attr = typeArg.GenericParameterAttributes;&lt;br /&gt;&lt;br /&gt;        if ((attr &amp;amp; GenericParameterAttributes.DefaultConstructorConstraint) != &lt;br /&gt;            GenericParameterAttributes.None)&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine("Default constructor constraint specified.");&lt;br /&gt;        }&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        if ((attr &amp;amp; GenericParameterAttributes.ReferenceTypeConstraint) != &lt;br /&gt;            GenericParameterAttributes.None)&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine("Reference type constraint specified.");&lt;br /&gt;        }&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        if ((attr &amp;amp; GenericParameterAttributes.NotNullableValueTypeConstraint) != &lt;br /&gt;            GenericParameterAttributes.None)&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine("Value type constraint specified.");&lt;br /&gt;        }&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        Type[] typeConstraints = typeArg.GetGenericParameterConstraints();&lt;br /&gt;        if (typeConstraints.Length &gt; 0)&lt;br /&gt;        {&lt;br /&gt;            foreach (Type typeConstraint in typeConstraints)&lt;br /&gt;            {&lt;br /&gt;                Console.WriteLine("Type Constraint : {0}", typeConstraint.FullName);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine("No type constraint specified.");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Run the following code with &lt;i&gt;&lt;b&gt;PrintingDevice&lt;/b&gt;&lt;/i&gt;,&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;Type t = typeof(PrintingDevice&lt;&gt;);&lt;br /&gt;DumpType(t);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and the outcome will be :&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;Is Generic Type : True&lt;br /&gt;Type Name : GenericConstraint.PrintingDevice`1&lt;br /&gt;Number of type parameter : 1&lt;br /&gt;Is Generic Parameter : True&lt;br /&gt;Default constructor constraint specified.&lt;br /&gt;Reference type constraint specified.&lt;br /&gt;Type Constraint : GenericConstraint.IPrint&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Run the code again with &lt;i&gt;&lt;b&gt;ValueGenericType&lt;/b&gt;&lt;/i&gt;,&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;Type t = typeof(ValueGenericType&lt;&gt;);&lt;br /&gt;DumpType(t);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and the outcome will be :&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;Is Generic Type : True&lt;br /&gt;Type Name : GenericConstraint.ValueGenericType`1&lt;br /&gt;Number of type parameter : 1&lt;br /&gt;Is Generic Parameter : True&lt;br /&gt;Default constructor constraint specified.&lt;br /&gt;Value type constraint specified.&lt;br /&gt;Type Constraint : System.ValueType&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;Type.GetGenericArguments()&lt;/b&gt;&lt;/i&gt; will return an array of type parameters specified for the generic type.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;Type.IsGenericParameter&lt;/b&gt;&lt;/i&gt; will return true if the current type represent a type parameter. If the type represent a type parameter, then the type will have no name.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;Type.GenericParameterAttributes&lt;/b&gt;&lt;/i&gt; will return the constraints specified for that type parameter.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;Type.GetGenericParameterConstraints()&lt;/b&gt;&lt;/i&gt; will return an array of type that are specified as the constraint for the type parameter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-4622131595745906681?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/4622131595745906681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=4622131595745906681' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4622131595745906681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4622131595745906681'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/09/reflection-on-generic-part-1-reflecting.html' title='Reflection on Generic, Part 2 - Reflecting Type Parameter'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-875859349344907410</id><published>2007-09-02T17:14:00.000+08:00</published><updated>2007-09-02T21:02:05.887+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>Reflection on Generic, Part 1</title><content type='html'>You can use reflection against generic type to get metadata information about a generic type as well as instantiate a generic type with type argument. In this post, I will walk you through how to retrieve metadata about a generic type.&lt;br /&gt;&lt;br /&gt;To check whether a type is a generic type, you use the &lt;i&gt;&lt;b&gt;Type.IsGenericType&lt;/b&gt;&lt;/i&gt; property.&lt;br /&gt;Let start with a simple example:&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;Type s = typeof(string);&lt;br /&gt;// This will print False.&lt;br /&gt;Console.WriteLine(s.IsGenericType);&lt;br /&gt;// This will print System.String&lt;br /&gt;Console.WriteLine(s.FullName);    &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Since System.String is not a generic type, it will print False. Now let's use an example with generic type:&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;Type t = typeof(List&amp;lt;&amp;gt;);&lt;br /&gt;// This will print True.    &lt;br /&gt;Console.WriteLine(t.IsGenericType);&lt;br /&gt;// This will print System.Collections.Generic.List`1.    &lt;br /&gt;Console.WriteLine(t.FullName);&lt;br /&gt;&amp;nbsp;    &lt;br /&gt;Type d = typeof(Dictionary&amp;lt;,&amp;gt;);&lt;br /&gt;// This will print True.    &lt;br /&gt;Console.WriteLine(d.IsGenericType);        &lt;br /&gt;// This will print System.Collections.Generic.Dictionary`2.    &lt;br /&gt;Console.WriteLine(d.FullName);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above example, both will print True. Note that to retrieve type metadata for a generic type, you need to use the &amp;lt;&amp;gt; after the generic type name to denote the number of type parameters specified for that generic type. The number of type parameters are part of the type signature. It is perfectly legal to declare the following:&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER: 1px solid"&gt;class C1&amp;lt;Y&amp;gt; { ... }&lt;br /&gt;class C1&amp;lt;Y,T&amp;gt; { ... }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Going back to the example, since &lt;i&gt;&lt;b&gt;List&lt;/b&gt;&lt;/i&gt; only has one type paratemer, I just specify &amp;lt;&amp;gt; to indicate I want to the List generic class with one type parameter. For &lt;i&gt;&lt;b&gt;Dictionary&lt;/b&gt;&lt;/i&gt; class take take two type parameter, I specify &amp;lt;,&amp;gt; to indicate I want the Dictionary generic class with two type parameter.&lt;br /&gt;&lt;br /&gt;When print out the full name of the class, notice that there is a number at the end of the class name. The number is called Arity which indicate the number of type parameter that the generic type have.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-875859349344907410?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/875859349344907410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=875859349344907410' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/875859349344907410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/875859349344907410'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/09/reflection-on-generic-part-1.html' title='Reflection on Generic, Part 1'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-4652081451773482143</id><published>2007-09-01T22:03:00.000+08:00</published><updated>2007-09-01T22:04:21.309+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Product Development'/><title type='text'>Commodity and Differentiation feature</title><content type='html'>Mainly, we can divide product features set into 2 category: Commodity and Differentiation. Commodity is the set of core features that every product that play in that market space must have. For example, if you are developing a word processor, content formatting capability is a must; If you are developing a CRM product, ability to track contact and opportunity is a must. Customer always expects the feature will be there in the product. It is not compelling to have them, but surprise of not to have them.&lt;br /&gt;&lt;br /&gt;Differentiation, as its spelled, is product feature that differentiate one product from another. Differentiation feature is what that give a product market advantage or to serve a niche in the market space. It is the type of feature that:&lt;br /&gt;a) Nice to have but not essential to product of that class. &lt;br /&gt;b) Allow the product company to charge more for their product.&lt;br /&gt;c) If implemented correctly and used to maximum advantage, it can redefine the game, become a commodity and possibly turn the company to become the market leader.&lt;br /&gt;&lt;br /&gt;For example, in a word processing product, it is nice but not essential to have a full drawing and diagramming capability. User who write article or book need to have both content formatting capability and graphics drawing capability within the same product because they need to have illustration for their content. Usually, they don't mind to pay a little more to get the extra feature that they want. But for majority of user, they might not need this capability to be included.&lt;br /&gt;&lt;br /&gt;Commodity feature can also be implemented in different product in different ways to include different functions and capabilities which in turn can become a differentiation fact. For example, in automobile industry, airbag is a commodity feature because it is an essential safety feature. You can't sell a car if you don't have airbag. However, while most cars have only one airbag at the driver seat, having the second airbag at front passenger seat is a compelling safety feature (This is just a hypothetical example. This is true many years ago, but today most car have two airbag as standard).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-4652081451773482143?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/4652081451773482143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=4652081451773482143' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4652081451773482143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/4652081451773482143'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/09/commodity-and-differentiation-feature.html' title='Commodity and Differentiation feature'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-1163473372785221202</id><published>2007-09-01T22:00:00.000+08:00</published><updated>2007-09-01T22:01:41.716+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Product Development'/><title type='text'>Product Planning : Vision first, not Feature first.</title><content type='html'>I believe that for a product to be successful, it is very important to get the product planning right. Product planning is the first activity when product team starts to think what to build for vNext or vNext+1 release.&lt;br /&gt;&lt;br /&gt;Some people start this activity by listing down a list of features that they think they want to include for the next release. While feature list is important, I don't think that is the right way to start. Customer does not buy software product just because it has cool feature, but because the product itself has a compelling story that make them to be more productive.&lt;br /&gt;&lt;br /&gt;Given the feature list, now the question is what features we should deliver for the next release to make it more compelling? Some people will look at their resource and time availability and pick a set of feature that can be delivered with that time frame. The problem with this approach is that your product may end up with a set of dis-integrated features and perceived as half baked.&lt;br /&gt;&lt;br /&gt;So what you can do about it? Remember in the first paragraph: the product itself need to have a compelling story to tell for it to be attractive. You marketing guy need to be able to articulate a smooth flowing story to their customer where they can show how various features and functions can be used in a coherent way. To achieve this, you need to have a product vision.&lt;br /&gt;&lt;br /&gt;Product vision describe what you want the product to be able to do for your customer and how far you want to take the product to. From the product vision, you derive a set of core values that deliver to that vision. Then you look at what features and functions are important in order to materialize the core values.&lt;br /&gt;&lt;br /&gt;Product vision is important for the following aspects:&lt;br /&gt;&lt;br /&gt;a) It allows you to articulate a simple message to your customer. Customer can clearly see what you are doing and be less confused.&lt;br /&gt;&lt;br /&gt;b) Your customer can easily see whether what you deliver is align to what they want. Successful company treats their customer as their partner. They share vision, roadmap and progress with their customer so that they can engage in a stronger long term relationship and move forward together. As a customer, you don't just to pay money to get some products. You want to ensure your vendor is able to help you to be successful.&lt;br /&gt;&lt;br /&gt;c) Product vision allows you to clearly identify the strength and short coming of your product. If give you a roadmap of what you should do next to improve the product in the future.&lt;br /&gt;&lt;br /&gt;d) Product vision establishes a single view point for all people in the team. Whatever role your team member is in the product group, all of them are able to articulate the same message when asked. And more importantly, no people will be lost at direction.&lt;br /&gt;&lt;br /&gt;e) It give you a focus point for not to be diverted by distraction. If there is a sudden market change, you can easily see whether the changes will actually affect you and what you can do to re-align your goal with the market.&lt;br /&gt;&lt;br /&gt;f) It give you a base to prioritize you feature. Features and functions that do not fit to materialize the vision should be at low priority.&lt;br /&gt;&lt;br /&gt;g) If your developers are faced with conflict and hard design decision, they can make the decision based on which materialize the vision better.&lt;br /&gt;&lt;br /&gt;It is important that the product vision is spread as wide as possible so that everyone can march in the same direction. Product vision that is not shared by everybody in the team is as good as none. How can you be motivated and convinced if you don't know where you are going and what you are contributing to. &lt;br /&gt;&lt;br /&gt;But what if you are a solution or consulting house? What if you are not building product, rather you build custom software or implement third party software product as solution to your customer? How does this apply to you?&lt;br /&gt;&lt;br /&gt;In such cases, it is important you first understand their business problem, the environment they are operating under, what is their IT direction and what they hope to achieve from the solution. Then you derive a solution map that correspond to their business and IT goal. Your solution map consists of a set of milestones each with specific goal and deliverables and you deliver based on that promise. This approach can form a healthy strong and long term relationship with your customer because both have a common understanding and expectation as early as the project start. In case their business environment and competitive surface change, it allows you and your customer to easily re-prioritize each other goal and evolve the relationship without hurting each other benefits.&lt;br /&gt;&lt;br /&gt;Business agility is the ability to adapt to changing business environment and accept the fact that change is part of the game. However, you can only change and understand the change impact if you have some sort of ground work to based upon for assessment. After all, how can you change course if you don't even know where you are heading. Product vision gives you this ground work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-1163473372785221202?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/1163473372785221202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=1163473372785221202' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1163473372785221202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1163473372785221202'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/09/product-planning-vision-first-not.html' title='Product Planning : Vision first, not Feature first.'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-2564875559925919856</id><published>2007-08-31T09:41:00.000+08:00</published><updated>2007-09-01T23:39:43.117+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Product Development'/><title type='text'>Product Development vs Software Development</title><content type='html'>In software business, a lot of people use the term product development and software development synonymously. However, IMHO, I think it is two distinct discipline or job. &lt;br /&gt;&lt;br /&gt;Software development mainly consist of major phases and activities such as understanding requirements, software design and architecture, coding, testing, QA and other engineering practices such as performance and technical benchmarking.&lt;br /&gt;&lt;br /&gt;However, in software business, simply developing and shipping software is not enough to keep the company going. The company needs not just to develop the software, but to develop a product.&lt;br /&gt;&lt;br /&gt;Product development include activities such as analyzing market trends and customer need, crafting a product vision of what you want to deliver and how you differentiate from your competitors, creating market awareness and communicating your vision to your customers, develop a strategy to capture and fulfill the market need, platform to deliver the product and of course shipping the product just in time to capture the market.&lt;br /&gt;&lt;br /&gt;Once you have the software piece ready to ship, you also need to make sure you have the necessary infrastructure to support your software, for example training your customer support personnel, documentation, maintenance release, and channel for customer to provide feedback and so on.&lt;br /&gt;&lt;br /&gt;Then, you need a plan to nurture the product. This includes branding; strengthen the customer relationship, making the product more mature by fixing short coming and incorporating customer feedback and so on.&lt;br /&gt;&lt;br /&gt;All these are part of the product development activities.&lt;br /&gt;&lt;br /&gt;To sum up, I would like to use the following diagram to illustrate my point:&lt;br&gt;&lt;br /&gt;&lt;a href="http://bp2.blogger.com/_jRUlOncToWc/RtdyG4OuFqI/AAAAAAAAABQ/OzXFS-LFzwA/s1600-h/product_dev.gif" target="_blank"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_jRUlOncToWc/RtdyG4OuFqI/AAAAAAAAABQ/OzXFS-LFzwA/s320/product_dev.gif" border="0" id="BLOGGER_PHOTO_ID_5104674165146654370" alt="Product Development vs Software Development"/&gt;&lt;br&gt;&lt;br&gt;Click to view in full size.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-2564875559925919856?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/2564875559925919856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=2564875559925919856' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/2564875559925919856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/2564875559925919856'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/08/product-development-vs-software.html' title='Product Development vs Software Development'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_jRUlOncToWc/RtdyG4OuFqI/AAAAAAAAABQ/OzXFS-LFzwA/s72-c/product_dev.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-6564672170298632833</id><published>2007-08-30T00:29:00.001+08:00</published><updated>2007-09-02T21:02:24.264+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>NET: Checking what is the type argument</title><content type='html'>The following code sample show how you can check what is the type of the type argument passed to instantiate the generic type.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border : 1px solid"&gt;&lt;br /&gt;public class TypeDisplayer&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt;    public string GetTypeArgument() { return typeof(T).FullName; } &lt;br /&gt;}&lt;br /&gt;&amp;nbsp;      &lt;br /&gt;static void ShowGenericTypeArgument()&lt;br /&gt;{&lt;br /&gt;    //This will print System.Int32.&lt;br /&gt;    TypeDisplayer&amp;lt;int&amp;gt; i = new TypeDisplayer&amp;lt;int&amp;gt;();&lt;br /&gt;    Console.WriteLine(i.GetTypeArgument());&lt;br /&gt;&amp;nbsp; &lt;br /&gt;    //This will print System.String.&lt;br /&gt;    TypeDisplayer&amp;lt;string&amp;gt; s = new TypeDisplayer&amp;lt;string&amp;gt;();&lt;br /&gt;    Console.WriteLine(s.GetTypeArgument());&lt;br /&gt;}    &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-6564672170298632833?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/6564672170298632833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=6564672170298632833' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/6564672170298632833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/6564672170298632833'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/08/net-checking-what-is-type-argument.html' title='NET: Checking what is the type argument'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-7067679784775031695</id><published>2007-08-30T00:19:00.001+08:00</published><updated>2007-09-02T21:02:33.661+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>NET: Generic Constraint Type - Default Constructor Constraint Type</title><content type='html'>Default Constructor constraint allow you to specify that the type parameter must have a default/parameterless constructor. This is useful if you want to create a new object instance of the type argument.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border : 1px solid"&gt;&lt;br /&gt;public class DefaultConstructorGenericType&amp;lt;T&amp;gt; where T : new()&lt;br /&gt;{&lt;br /&gt;    public T Value;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    public DefaultConstructorGenericType()&lt;br /&gt;    {&lt;br /&gt;        Value = new T();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;public class ClassWithDefaultCon&lt;br /&gt;{&lt;br /&gt;    public ClassWithDefaultCon() {}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class ClassB&lt;br /&gt;{&lt;br /&gt;    public int a;&lt;br /&gt;    public ClassB(int v) { a = v;}&lt;br /&gt;}  &lt;br /&gt;&amp;nbsp;&lt;br /&gt;static void InstantiateDefault()&lt;br /&gt;{&lt;br /&gt;    // This code will compile fine.&lt;br /&gt;    DefaultConstructorGenericType&amp;lt;ClassWithDefaultCon&amp;gt; vt =&lt;br /&gt;        new DefaultConstructorGenericType&amp;lt;ClassWithDefaultCon&amp;gt;();&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    // This code will give compile error &lt;br /&gt;    // because ClassB does not have default constructor&lt;br /&gt;    DefaultConstructorGenericType&amp;lt;ClassB&amp;gt; vt =&lt;br /&gt;        new DefaultConstructorGenericType&amp;lt;ClassB&amp;gt;();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;    &lt;br /&gt;&lt;br /&gt;In the above sample, &lt;i&gt;&lt;b&gt;DefaultConstructorGenericType&lt;/b&gt;&lt;/i&gt; can only accept a type argument that has a default constructor. &lt;i&gt;&lt;b&gt;where&lt;/b&gt;&lt;/i&gt; keyword is used to specify a generic constraint in C#. In the above code sample, I specify that type parameter T has to have default constructor (indicate by &lt;i&gt;&lt;b&gt;where T : new()&lt;/b&gt;&lt;/i&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-7067679784775031695?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/7067679784775031695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=7067679784775031695' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/7067679784775031695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/7067679784775031695'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/08/net-generic-constraint-type-default.html' title='NET: Generic Constraint Type - Default Constructor Constraint Type'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-3537878307629137071</id><published>2007-08-29T23:41:00.000+08:00</published><updated>2007-09-02T21:02:44.484+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>NET: Generic Constraint Type - Inheritance Constraint Type</title><content type='html'>Inheritance type constraint allow you to specify that the type parameter must be derive from certain base class or interface. It is useful if you want to assume the type argument to be of certain type so that you can call method on the instance of the type argument. Visual Studio will give you full intellisense support.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;public interface IPrint&lt;br /&gt;{&lt;br /&gt;    void Print();&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;public class Printer : IPrint&lt;br /&gt;{&lt;br /&gt;    public void Print()&lt;br /&gt;    {&lt;br /&gt;        // Do something&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;public class PhotoCopier&lt;br /&gt;{&lt;br /&gt;    public void PhotoCopy()&lt;br /&gt;    {&lt;br /&gt;        // Do something.&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;public class DeviceWrapper&amp;lt;T&amp;gt; where T : IPrint&lt;br /&gt;{&lt;br /&gt;    public T Device;&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;static void InstantiateDevice()&lt;br /&gt;{&lt;br /&gt;    // This code will compile fine.&lt;br /&gt;    DeviceWrapper&amp;lt;Printer&amp;gt; vt =&lt;br /&gt;        new DeviceWrapper&amp;lt;Printer&amp;gt;();&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    // This code will give compile error&lt;br /&gt;    // because PhotoCopier is not derive from IPrint.&lt;br /&gt;    DeviceWrapper&amp;lt;PhotoCopier&amp;gt; vt2 =&lt;br /&gt;        new DeviceWrapper&amp;lt;PhotoCopier&amp;gt;();&lt;br /&gt;}   &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above sample, &lt;i&gt;&lt;b&gt;DeviceWrapper&lt;/b&gt;&lt;/i&gt; can only accept a type argument that is derive from &lt;i&gt;&lt;b&gt;IPrint&lt;/b&gt;&lt;/i&gt;.&lt;br /&gt;&lt;i&gt;&lt;b&gt;where&lt;/b&gt;&lt;/i&gt; keyword is used to specify a generic constraint in C#. In the above code sample, I specify that&lt;br /&gt;type parameter T has to be derive from &lt;i&gt;&lt;b&gt;IPrint&lt;/b&gt;&lt;/i&gt; (indicate by &lt;i&gt;&lt;b&gt;where T : IPrint&lt;/b&gt;&lt;/i&gt;).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img alt="Visual Studio Intellisense support" src="http://bp2.blogger.com/_jRUlOncToWc/RtWZQYOuFpI/AAAAAAAAABI/zqJXpaVy6No/s320/generic_inheritance_constraint.JPG" /&gt;&lt;br /&gt;Visual Studio Intellisense support.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-3537878307629137071?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/3537878307629137071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=3537878307629137071' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/3537878307629137071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/3537878307629137071'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/08/net-generic-constraint-type-inheritance.html' title='NET: Generic Constraint Type - Inheritance Constraint Type'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_jRUlOncToWc/RtWZQYOuFpI/AAAAAAAAABI/zqJXpaVy6No/s72-c/generic_inheritance_constraint.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-5138941951144890904</id><published>2007-08-29T23:25:00.000+08:00</published><updated>2007-09-02T21:02:53.272+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>NET: Generic Constraint Type - Reference Constraint Type</title><content type='html'>Reference type constraint allow you to specify that the type parameter must be of reference type.&lt;br /&gt;&lt;pre style="border : 1px solid"&gt;&lt;br /&gt;class GenericReferenceType&amp;lt;T&amp;gt; where T : class&lt;br /&gt;{&lt;br /&gt;    public T Value;&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;static void InstantiateRefType()&lt;br /&gt;{&lt;br /&gt;    // This code will compile fine.&lt;br /&gt;    GenericReferenceType&amp;lt;System.Text.StringBuilder&amp;gt; vt =&lt;br /&gt;        new GenericReferenceType&amp;lt;StringBuilder&amp;gt;();&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    // This code will give compile error &lt;br /&gt;    //because Point is not reference type.&lt;br /&gt;    GenericReferenceType&amp;lt;System.Drawing.Point&amp;gt; vt2 =&lt;br /&gt;        new GenericReferenceType&amp;lt;System.Drawing.Point&amp;gt;();&lt;br /&gt;}    &lt;br /&gt;&lt;/pre&gt;  &lt;br /&gt;&lt;br /&gt;In the above sample, &lt;i&gt;&lt;b&gt;GenericReferenceType&lt;/b&gt;&lt;/i&gt; can only accept a reference type as its type parameter.&lt;br /&gt;&lt;i&gt;&lt;b&gt;where&lt;/b&gt;&lt;/i&gt; keyword is used to specify a generic constraint in C#. In the above code sample, I specify that&lt;br /&gt;type parameter T has to be of reference type (indicate by &lt;i&gt;&lt;b&gt;where T : class&lt;/b&gt;&lt;/i&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-5138941951144890904?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/5138941951144890904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=5138941951144890904' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/5138941951144890904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/5138941951144890904'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/08/net-generic-constraint-type-reference.html' title='NET: Generic Constraint Type - Reference Constraint Type'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-5393968019579678359</id><published>2007-08-29T23:19:00.000+08:00</published><updated>2007-09-02T21:03:09.795+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>NET: Introduction to Generic Constraint Type</title><content type='html'>Generic constraint allow you to specify constraint/rule that limit what .net type can be used as type argument when you instantiate a generic type.&lt;br /&gt;&lt;br /&gt;In this post, I will show a short code sample of how to use the various generic constraint.&lt;br /&gt;For more explaination about Generic Constraint, visit &lt;a href="http://msdn2.microsoft.com/en-us/library/d5x73970(VS.80).aspx" target="_blank"&gt;msdn&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;How to specify constraint value type&lt;/h2&gt;&lt;br /&gt;Value type constraint allow you to specify that the type parameter must be of value type.&lt;br /&gt;&lt;pre style="border : 1px solid"&gt;&lt;br /&gt;class GenericValueType&amp;lt;T&amp;gt; where T : struct&lt;br /&gt;{&lt;br /&gt;    public T Value;&lt;br /&gt;}&lt;br /&gt;&amp;nbsp;&lt;br /&gt;static void InstantiateValueType()&lt;br /&gt;{&lt;br /&gt;    // This code will compile fine.&lt;br /&gt;    GenericValueType&amp;lt;System.Drawing.Point&amp;gt; vt = &lt;br /&gt;        new GenericValueType&amp;lt;System.Drawing.Point&amp;gt;();&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    // This code will give compile error &lt;br /&gt;    //because StringBuilder is not value type.&lt;br /&gt;    GenericValueType&amp;lt;System.Text.StringBuilder&amp;gt; vt2 = &lt;br /&gt;        new GenericValueType&amp;lt;StringBuilder&amp;gt;();&lt;br /&gt;}    &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;where&lt;/b&gt;&lt;/i&gt; keyword is used to specify a generic constraint in C#. In the above code sample, I specify that type parameter T has to be of value type (indicate by &lt;i&gt;&lt;b&gt;where T : struct&lt;/b&gt;&lt;/i&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-5393968019579678359?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/5393968019579678359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=5393968019579678359' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/5393968019579678359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/5393968019579678359'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/08/net-introduction-to-generic-constraint.html' title='NET: Introduction to Generic Constraint Type'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-6724909837111467195</id><published>2007-07-11T21:30:00.000+08:00</published><updated>2007-07-11T21:32:09.572+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Office'/><title type='text'>Outlook : Display Add-in error in Outlook 2007</title><content type='html'>If you develop Ribbon UI in Outlook 2007&lt;br /&gt;and you want to see any error message resulted from&lt;br /&gt;mis-programming the Ribbon, you have to enable the &lt;br /&gt;&lt;i&gt;Show add-in user interface errors&lt;/i&gt; option.&lt;br /&gt;&lt;br /&gt;To do this,&lt;br /&gt;goto Tools -&gt; Options,&lt;br /&gt;Select &lt;i&gt;Other&lt;/i&gt; tab, Click on &lt;i&gt;Advance options&lt;/i&gt;,&lt;br /&gt;then tick &lt;i&gt;Show add-in user interface errors&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-6724909837111467195?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/6724909837111467195/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=6724909837111467195' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/6724909837111467195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/6724909837111467195'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/07/outlook-display-add-in-error-in-outlook.html' title='Outlook : Display Add-in error in Outlook 2007'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-1090914648925455970</id><published>2007-02-27T21:34:00.000+08:00</published><updated>2007-02-27T21:47:09.114+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><title type='text'>NET : Ignore field for XML Serialization</title><content type='html'>You can ignore certain public field from being serialize if the value for that field&lt;br /&gt;is not specified.&lt;br /&gt;&lt;br /&gt;XmlSerializer recognize a specific pattern during serialization to ignore&lt;br /&gt;or include a field into the serialization.&lt;br /&gt;&lt;br /&gt;Here are the steps :&lt;br /&gt;1) You create a public field (EG : public int Age).&lt;br /&gt;2) Create a boolean field using the convention &lt;i&gt;PropertyName&lt;/i&gt;Specified (EG : public boolean AgeSpecified).&lt;br /&gt;3) Apply &lt;i&gt;XmlIgnoreAttribute&lt;/i&gt; attribute to the boolean property.&lt;br /&gt;&lt;br /&gt;Refer to the following code.&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;public class Customer&lt;br /&gt;{&lt;br /&gt;    public string Name;&lt;br /&gt;    public int Age;&lt;br /&gt;&lt;br /&gt;    [XmlIgnore()]&lt;br /&gt;    public bool AgeSpecified;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here is the code to serialize the Customer object. Notice I set the AgeSpecified to false to tell the XmlSerializer not to serialize the Age field.&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;static void SerializeData()&lt;br /&gt;{&lt;br /&gt;    Customer c = new Customer();&lt;br /&gt;    c.Name = "Bob";&lt;br /&gt;    c.Age = 21;&lt;br /&gt;    c.AgeSpecified = false;&lt;br /&gt;&lt;br /&gt;    XmlSerializer serializer = new XmlSerializer(typeof(Customer));&lt;br /&gt;    FileStream fs = new FileStream("simple.xml", FileMode.Create);&lt;br /&gt;&lt;br /&gt;    // Serialize the object&lt;br /&gt;    serializer.Serialize(fs, c);&lt;br /&gt;    fs.Close();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you open simple.xml in notepad, you will see that there is no Age field.&lt;br /&gt;&lt;BR&gt;&lt;br /&gt;&lt;img src="http://bp1.blogger.com/_jRUlOncToWc/ReQz5GbT0cI/AAAAAAAAAAM/5PHkp8jH0YU/s320/unspecified_s.jpg"/&gt;&lt;br /&gt;&lt;BR&gt;&lt;br /&gt;Run the following code to deserialize the object from the file.&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;static void DeserializeData()&lt;br /&gt;{&lt;br /&gt;    Customer c = null;&lt;br /&gt;&lt;br /&gt;    XmlSerializer serializer = new XmlSerializer(typeof(Customer));&lt;br /&gt;    FileStream fs = new FileStream("simple.xml", FileMode.Open);&lt;br /&gt;&lt;br /&gt;    c = (Customer)serializer.Deserialize(fs);&lt;br /&gt;    fs.Close();&lt;br /&gt;&lt;br /&gt;    Console.WriteLine("Age : " + c.Age);&lt;br /&gt;    Console.WriteLine("Specified : " + c.AgeSpecified);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://bp1.blogger.com/_jRUlOncToWc/ReQz5GbT0dI/AAAAAAAAAAU/Se6HBWG8oAQ/s320/unspecified_ds.jpg"/&gt;&lt;br /&gt;&lt;BR&gt;&lt;br /&gt;Now run the serialize and deserialize code again, but this time set the AgeSpecified to true, and below is&lt;br /&gt;the output :&lt;br /&gt;&lt;BR&gt;&lt;br /&gt;&lt;img src="http://bp2.blogger.com/_jRUlOncToWc/ReQz5WbT0eI/AAAAAAAAAAc/Y2Ow2JuLnZY/s320/specified_s.jpg"/&gt;&lt;BR&gt;&lt;br /&gt;&lt;img src="http://bp2.blogger.com/_jRUlOncToWc/ReQz5WbT0fI/AAAAAAAAAAk/eLgSXemxAxE/s320/specified_ds.jpg"/&gt;&lt;BR&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-1090914648925455970?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/1090914648925455970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=1090914648925455970' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1090914648925455970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/1090914648925455970'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/02/you-can-ignore-certain-public-field.html' title='NET : Ignore field for XML Serialization'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_jRUlOncToWc/ReQz5GbT0cI/AAAAAAAAAAM/5PHkp8jH0YU/s72-c/unspecified_s.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-117068769132882143</id><published>2007-02-05T22:49:00.000+08:00</published><updated>2007-02-27T20:54:22.864+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><title type='text'>Exception : {Throw} vs {Throw ex}</title><content type='html'>I have seen two way how people typically throw exception:&lt;br /&gt;&lt;br /&gt;Example 1:&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;try&lt;br /&gt;{&lt;br /&gt;    //...&lt;br /&gt;}&lt;br /&gt;catch(Exception ex)&lt;br /&gt;{&lt;br /&gt;    throw;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Example 2:&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;try&lt;br /&gt;{&lt;br /&gt;    //...&lt;br /&gt;}&lt;br /&gt;catch(Exception ex)&lt;br /&gt;{&lt;br /&gt;    throw ex;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;While both accomplish the objective, which is to throw the exception back to the&lt;br /&gt;caller for further action, it has substle difference.&lt;br /&gt;&lt;br /&gt;In the first example, it is considered you are re-throwing the existing exception.&lt;br /&gt;The exception contain the full stack frame from where the exception is orginated&lt;br /&gt;all the way up to the caller stack frame.&lt;br /&gt;&lt;br /&gt;Run the sample code below, and you shall see the stack trace as below. Notice, at each stack frame, the stack trace contain the stack frame of where the exception is orginated all the way up to the caller stack frame.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos1.blogger.com/x/blogger/6506/485/1600/178393/throw.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;In the second example, it is considered you are throwing a new exception.&lt;br /&gt;The exception only contain stack frame of the caller and the frame which throw&lt;br /&gt;the exception. Run the sample code again, but this time change the &lt;i&gt;throw&lt;/i&gt; to &lt;i&gt;throw ex&lt;/i&gt;. This time, you will notice at each stack frame, the stack trace only contain the stack frame of the callee and the caller. So, you lose information of where the exception is originated. This can make locating the source of error very difficult.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos1.blogger.com/x/blogger/6506/485/1600/597178/throw_ex.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;Sample Code&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;class Class1&lt;br /&gt;{&lt;br /&gt;    [STAThread]&lt;br /&gt;    static void Main(string[] args)&lt;br /&gt;    {&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine(f1());&lt;br /&gt;        }&lt;br /&gt;        catch(Exception ex)&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine("---Exception in Main()---");&lt;br /&gt;            Console.WriteLine(ex.Message);&lt;br /&gt;            Console.WriteLine(ex.StackTrace.ToString());&lt;br /&gt;        }&lt;br /&gt;        Console.ReadLine();  &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static int f1()&lt;br /&gt;    {&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            return f2();&lt;br /&gt;        }&lt;br /&gt;        catch(Exception ex)&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine("---Exception in f1()---");&lt;br /&gt;            Console.WriteLine(ex.Message);&lt;br /&gt;            Console.WriteLine(ex.StackTrace.ToString());&lt;br /&gt;            throw;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static int f2()&lt;br /&gt;    {&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            return f3();&lt;br /&gt;        }&lt;br /&gt;        catch(Exception ex)&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine("---Exception in f2()---");&lt;br /&gt;            Console.WriteLine(ex.Message);&lt;br /&gt;            Console.WriteLine(ex.StackTrace.ToString());&lt;br /&gt;            throw;&lt;br /&gt;        }           &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static int f3()&lt;br /&gt;    {&lt;br /&gt;        int a = 0;&lt;br /&gt;        int b = 1;&lt;br /&gt;&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            return b /a;&lt;br /&gt;        }&lt;br /&gt;        catch(Exception ex)&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine("---Exception in f3()---");&lt;br /&gt;            Console.WriteLine(ex.Message);&lt;br /&gt;            Console.WriteLine(ex.StackTrace.ToString());&lt;br /&gt;            throw;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-117068769132882143?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/117068769132882143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=117068769132882143' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/117068769132882143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/117068769132882143'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/02/exception-throw-vs-throw-ex.html' title='Exception : {Throw} vs {Throw ex}'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-117012664297218948</id><published>2007-01-30T11:08:00.000+08:00</published><updated>2007-02-27T20:56:20.029+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='aspnet'/><title type='text'>ASPNET: Maintain Page position on Postback</title><content type='html'>When you have a long web page, you might want to maintain the page position after the post back so that tbe user does not have to scroll down to the page again. This is a very important usability issue.&lt;br /&gt;&lt;br /&gt;In ASP.NET 1.1, you can achieve this using the SmartNavigation page directive:&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;&amp;lt;%@ Page Language="C#" SmartNavigation="true"%&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;However, SmartNavigation require IE 5.5 or above.&lt;br /&gt;&lt;br /&gt;ASP.NET 2.0 introduce a new page directive call MaintainScrollPositionOnPostback which achive the same result.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;&amp;lt;%@ Page Language="C#" MaintainScrollPositionOnPostback="true" %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I tested MaintainScrollPositionOnPostback in both IE and Firefox and it work prefectly in both browser. Better still, you can enable this for all web pages in your web site by setting it in the web.config under &amp;lt;pages&amp;gt; element.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-117012664297218948?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/117012664297218948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=117012664297218948' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/117012664297218948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/117012664297218948'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2007/01/aspnet-maintain-page-position-on.html' title='ASPNET: Maintain Page position on Postback'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-116602150199146347</id><published>2006-12-13T22:42:00.000+08:00</published><updated>2007-02-27T21:21:46.368+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Calculating working days between 2 dates</title><content type='html'>Here is a function to calculate the number of working days given two dates. It assume the working days is from Monday to Friday, both dates are inclusive and no holidays in between.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;static int CalculateWorkingDays(DateTime start, DateTime end)&lt;br /&gt;{&lt;br /&gt;    DateTime firstSunday, lastSaturday;&lt;br /&gt;    int workDays = 0;&lt;br /&gt;&lt;br /&gt;    if (start.DayOfWeek != DayOfWeek.Sunday)&lt;br /&gt;    {&lt;br /&gt;        firstSunday = start.AddDays(7 - ((int)start.DayOfWeek));&lt;br /&gt;        workDays += (6 - (int)start.DayOfWeek);&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;        firstSunday = start;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    if (end.DayOfWeek != DayOfWeek.Saturday)&lt;br /&gt;    {&lt;br /&gt;        lastSaturday = end.AddDays(-((int)end.DayOfWeek) - 1);&lt;br /&gt;        workDays += (int)end.DayOfWeek;&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;        lastSaturday = end;&lt;br /&gt;&lt;br /&gt;    TimeSpan ts = lastSaturday.Subtract(firstSunday);&lt;br /&gt;    workDays += ((ts.Days + 1) / 7) * 5;&lt;br /&gt;&lt;br /&gt;    return workDays;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-116602150199146347?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/116602150199146347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=116602150199146347' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116602150199146347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116602150199146347'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/12/calculating-working-days-between-2.html' title='Calculating working days between 2 dates'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-116558742114056398</id><published>2006-12-08T22:09:00.000+08:00</published><updated>2007-02-27T21:20:46.071+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visualstudio'/><title type='text'>VS2005 : Reference .NET 3.0 Assemblies</title><content type='html'>I installed .NET Framework 3.0 just a while ago and I realize that the new assemblies in.NET 3.0 does not show in the Reference dialog box when you Add Reference in your VS 2005project.&lt;br /&gt;To enable this, you have to manually add a key into the registry. By default, when you install.NET 3.0, the assemblies is installed into the folder:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;To enable the 3.0 assemblies to show in the Reference dialog, create a .reg file and put the following into the file. Then double click the .reg file to merge it into the registry.&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;Windows Registry Editor Version 5.00&lt;br /&gt;[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\8.0\AssemblyFoldersFramework 3.0]&lt;br /&gt;@="C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\v3.0"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now restart yout Visual Studio 2005, create a new project or open any existing project,then open Add Reference dialog box in the project, you should now see the new 3.0 assemblies.&lt;br /&gt;&lt;br /&gt;&lt;img alt="VS 2005 Add Reference for .NET 3.0 assemblies." src="http://photos1.blogger.com/x/blogger/6506/485/1600/859797/vs_add_ref.jpg" border="0" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-116558742114056398?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/116558742114056398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=116558742114056398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116558742114056398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116558742114056398'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/12/vs2005-reference-net-30-assemblies.html' title='VS2005 : Reference .NET 3.0 Assemblies'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-116229507262981161</id><published>2006-11-01T18:00:00.000+08:00</published><updated>2007-02-27T20:56:27.768+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>Project : Using Lag and Lead Time</title><content type='html'>In the previous blog, I have explained about lag and lead time. In this blog, I will give you a scenario of how and when to use lag and lead, and how two schedule that use lag and lead although look the same, it is semantically different.&lt;br /&gt;&lt;br /&gt;Consider the following two schedules.&lt;br /&gt;&lt;br /&gt;Schedule 1&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/6506/485/1600/01-lag.1.jpg"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger/6506/485/1600/01-lag.1.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 1: This schedule use a finish-start relationship with a 1 day lead time.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Schedule 2&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/6506/485/1600/02-lead.2.jpg"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger/6506/485/1600/02-lead.2.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 2: This schedule use a start-start relationship with 4 days lag time.&lt;br /&gt;&lt;br /&gt;In both schedule, &lt;i&gt;Development&lt;/i&gt; task start on 6-Nov and &lt;i&gt;Testing&lt;/i&gt; task start on 10-Nov and they both look the same. From the schedule dates point of view, they can be considered same. However, from the schedule semantics point of view, they mean different thing. In schedule 1, my schedule says that &lt;i&gt;Testing&lt;/i&gt; should start one day before &lt;i&gt;Development&lt;/i&gt; finish (the successor task is relative to the finish of the predecessor). In schedule 2, my schedule says that &lt;i&gt;Testing&lt;/i&gt; should start four days after &lt;i&gt;Development&lt;/i&gt; start (the successor task is relative to the start of the predecessor).&lt;br /&gt;&lt;br /&gt;Now, let say I change my &lt;i&gt;Development&lt;/i&gt; task to 8 days. Here is how the new schedules look like:&lt;br /&gt;&lt;br /&gt;Schedule 1&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/6506/485/1600/03-lag-adjusted.2.jpg"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger/6506/485/1600/03-lag-adjusted.2.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 3: Testing now starts on 15-Nov.&lt;br /&gt;&lt;br /&gt;Schedule 2&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/6506/485/1600/04-lead_adjusted.2.jpg"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger/6506/485/1600/04-lead_adjusted.2.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 4: Testing still remains to start on 10-Nov.&lt;br /&gt;&lt;br /&gt;Now the dates in both schedule different. So, which is the correct way of scheduling? They are no right or wrong way, it all depends on what are you trying to express in your schedule (although in this case, Schedule 2 seem to be incorrect. How can you finish testing while development is still in progress?).&lt;br /&gt;&lt;br /&gt;If your successor task is relative to the finish of the predecessor task, then use finish-start relationship with lead time. For example, you can only start testing towards the near completion of development. If you start too early, you might not have enough things to test.&lt;br /&gt;&lt;br /&gt;If your successor task is relative to the start of the predecessor task, then use start-start relationship with lag. For example, you are very certain that as soon as your development has started for two days, you will have enough things to start testing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-116229507262981161?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/116229507262981161/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=116229507262981161' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116229507262981161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116229507262981161'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/11/project-using-lag-and-lead-time.html' title='Project : Using Lag and Lead Time'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-116229416955423108</id><published>2006-10-31T19:23:00.000+08:00</published><updated>2007-02-27T20:56:37.563+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>Project : Lag and Lead Time</title><content type='html'>Project : Lag and Lead Time&lt;br /&gt;&lt;br /&gt;In MS Project, when you establish a relationship between two tasks, you can specify a lag. Lag indicates the gap time between two tasks.&lt;br /&gt;&lt;br /&gt;You can specify lag in the Task Information -&gt; Predecessors tab:&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/6506/485/1600/01-lag-taskinfo.jpg"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger/6506/485/320/01-lag-taskinfo.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 1&lt;br /&gt;&lt;br /&gt;Or in the table view:&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/6506/485/1600/02-lag-tableview.jpg"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger/6506/485/320/02-lag-tableview.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 2&lt;br /&gt;&lt;br /&gt;There are two type of lag: delay and overlap.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Delay&lt;/b&gt; is indicated by a &lt;b&gt;positive lag value&lt;/b&gt; and is called &lt;b&gt;lag time&lt;/b&gt; in MS Project. It specifies that the successor task will start only after N days the predecessor task is completed (based on finish-start relationship). Figure 2 is an example of lag time (with positive two day lag).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Overlap&lt;/b&gt; is indicated by a &lt;b&gt;negative lag value&lt;/b&gt; and is called &lt;b&gt;lead time&lt;/b&gt; in MS Project. It specifies that the successor task will start N days before the predecessor task is completed (based on finish-start relationship). Figure 3 is an example of lead time (with negative one day lag).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/6506/485/1600/03-lead.jpg"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger/6506/485/320/03-lead.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 3&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-116229416955423108?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/116229416955423108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=116229416955423108' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116229416955423108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116229416955423108'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/10/project-lag-and-lead-time.html' title='Project : Lag and Lead Time'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-116140345712700462</id><published>2006-10-21T12:02:00.000+08:00</published><updated>2006-10-21T12:05:56.146+08:00</updated><title type='text'>Find out more about Bangkok</title><content type='html'>While looking for some information about the new Bangkok airport, I found this site which has some prety good information.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.into-asia.com/bangkok" target="_blank"&gt;http://www.into-asia.com/bangkok&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Interestingly enough, there is also a mention of social engineering plot targeted to tourist in Bangkok.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.into-asia.com/bangkok/gemscam" target="_blank"&gt;http://www.into-asia.com/bangkok/gemscam&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-116140345712700462?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/116140345712700462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=116140345712700462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116140345712700462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116140345712700462'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/10/find-out-more-about-bangkok.html' title='Find out more about Bangkok'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-116115149082496569</id><published>2006-10-18T13:58:00.000+08:00</published><updated>2007-02-27T21:21:41.160+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iis'/><title type='text'>IIS : Getting Physical Path for Virtual Directory in .NET</title><content type='html'>Here is a C# code sample of how to use System.DirectoryServices in .NET to get the physical path for IIS virtual directory.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Class1&lt;br /&gt;{&lt;br /&gt;    [STAThread]&lt;br /&gt;    static void Main(string[] args)&lt;br /&gt;    {&lt;br /&gt;        string serverComment = "Default Web Site";&lt;br /&gt;        string iisHost = "IIS://LocalHost";&lt;br /&gt;        string siteName = GetIISSiteName(iisHost, serverComment);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        Console.WriteLine(siteName);&lt;br /&gt;        if(siteName.Equals(String.Empty))&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine("Site not found.");&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            // Get the physical path for http://localhost/testemail&lt;br /&gt;            string path = GetVirtualDirPath(iisHost, siteName, "testemail");&lt;br /&gt;&lt;br /&gt;            if(path.Equals(String.Empty))&lt;br /&gt;                Console.WriteLine("VD not found.");&lt;br /&gt;            else&lt;br /&gt;                Console.WriteLine(path);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        Console.WriteLine("done");&lt;br /&gt;        Console.ReadLine();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    static string GetIISSiteName(string iisHost, string serverComment)&lt;br /&gt;    {&lt;br /&gt;        string adsiPath = iisHost + "/W3SVC";&lt;br /&gt;        DirectoryEntry entry = new DirectoryEntry(adsiPath);&lt;br /&gt;        foreach (DirectoryEntry site in entry.Children)&lt;br /&gt;        {&lt;br /&gt;            if (site.SchemaClassName == "IIsWebServer" &amp;&amp;amp;&lt;br /&gt;                site.Properties["ServerComment"].Value&lt;br /&gt;                .ToString().Equals(serverComment))&lt;br /&gt;            {&lt;br /&gt;                return site.Name;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return "";&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    static string GetVirtualDirPath(string iisHost,&lt;br /&gt;                                    string siteName, string vdName)&lt;br /&gt;    {&lt;br /&gt;        string adsiPath = iisHost + "/W3SVC/" + siteName + "/Root/" + vdName;&lt;br /&gt;&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            DirectoryEntry entry = new DirectoryEntry(adsiPath);&lt;br /&gt;            return entry.Properties["Path"].Value.ToString();&lt;br /&gt;        }&lt;br /&gt;        catch(Exception ex)&lt;br /&gt;        {&lt;br /&gt;            // If Virtual Directory is not found,&lt;br /&gt;            // it will throw exception.&lt;br /&gt;            return "";&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return "";&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-116115149082496569?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/116115149082496569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=116115149082496569' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116115149082496569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116115149082496569'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/10/iis-getting-physical-path-for-virtual.html' title='IIS : Getting Physical Path for Virtual Directory in .NET'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-116038029221504360</id><published>2006-10-16T23:00:00.000+08:00</published><updated>2007-02-27T21:21:18.572+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Social Engineering, Part 3</title><content type='html'>&lt;h3&gt;How to Identify Social Engineering Attempt&lt;/h3&gt;&lt;br /&gt;There are certain ways of how we can identify possible social engineering attempts. Although it is not fool proof, but will give us a sign of possibility of attempts.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Refusal to Give Callback Number&lt;/b&gt;&lt;br /&gt;Social engineer will always refuse to give call back number because this will leave trace of their presence. However, this method is not always true. With today convenience, the attack can simply buy a prepaid phone card for use in his action. After he is done, he can just throw it away.&lt;br /&gt;&lt;br /&gt;If you offer to call back the caller at a later time to provide him with the information he is asking for and he refuse to give his contact number, this act should immediately rise suspicious.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Out of Ordinary Request&lt;/b&gt;&lt;br /&gt;The goal of social engineering attack is to reveal information which normally difficult to get. If someone is asking for personal information or question which seems to be unrelated such as user name, password, server name or IC number, you should flag a red alarm and find out why the person need those information and look for ways to validate his true identity.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Claim of Authority&lt;/b&gt;&lt;br /&gt;The attacker claims that he is someone with authority or act on behalf of the authority. The attacker wills always emphasis on his authority and refuse to provide credential to proof his identity. He may also use the authority to threaten his target.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Threatens Negative Consequences of Non Compliance&lt;/b&gt;&lt;br /&gt;The attacker will use negative consequences to threaten his victim if his victim attempt not to comply with his request.&lt;br /&gt;&lt;br /&gt;For example, the attacker may threaten that if he cannot get his job done on time because you refuse to provide him with the information he need, then you will be answerable to the company CEO for your action.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Stress Urgency&lt;/b&gt;&lt;br /&gt;The attacker will make his request sounds very urgent and stress out his victim so that his victim will panic and reveal the information without careful thinking.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Name dropping&lt;/b&gt;&lt;br /&gt;Name dropping is a technique of using the name of someone who is close to the victim, or have authority over the victim or the victim is responsible for to gain information.&lt;br /&gt;&lt;br /&gt;For example, the attack could call the victim and say "Mr Big need this document by 3pm! He has authorized me to request the document from you!" If Mr Big is an important customer or executive to the victim, what are the chances that the victim will ever challenge that request?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;How to Combat and Prevent Social Engineering&lt;/h3&gt;&lt;br /&gt;There are certain ways if not eliminate, will certainly reduce the chance that you will be the next victim of social engineering attack.&lt;br /&gt;&lt;br /&gt;Training is the primary defense for combating against social engineering. Organize security awareness training and campaign to educate your staffs about social engineering, how to detect and combat it. The training needs to be an on-going program. It needs to be delivered at least once every year. Sophistication of social engineering attack will evolve as social engineer learn and become smarter. Your employees need to be updated with these new technique and knowledge to maintain security effectiveness.&lt;br /&gt;&lt;br /&gt;Prevent unauthorized access to office, mailroom, PBX room. The first defense to stop physical social engineering is to stop the attack from entering the office premise and sensitive area. Put up a policy to enforce every employee wear their badge in the office. Restrict employee access to sensitive area such as PBX room or computer data center. Empower employee to challenge anyone who show up in the restricted area without a valid badge.&lt;br /&gt;&lt;br /&gt;Do not leave sensitive or valuable information in open area. Information which can be used for social engineering attack such as address book, business documents, and employees contact list should be kept in the drawer. Always lock your computer and drawer when you are away from your desk.&lt;br /&gt;&lt;br /&gt;Do not release private information to stranger or someone you cannot confirm their identity. Do not trust who they claim to be unless you know them personally or you can recognize their voice on the phone. If someone is asking for a piece of information which you have access to but does not own it, do not ever give it out. Direct the requestor to the information owner. The information owner will have the discrete right to determine who has the need to know.&lt;br /&gt;&lt;br /&gt;Handle trash and rubbish with care. Invest in a more sophisticated shredder to shred the unwanted paper or documents. Do not leave your trash in public area where anybody can access. Classified information should be separated and only be handled by authorized personnel for disposal. If you are throwing out computer hardware or equipment, make sure you physically destroy the storage media such as hard disk and CD. Sophisticated software is available in the market to recover data in hard disk even though it has been formatted or deleted.&lt;br /&gt;&lt;br /&gt;Avoid using public computer. Public computer is most subjected to social engineering attack because anybody can have access to it. Spying software or keyboard logger can be silently installed in the public computer to monitor you keystroke and activities. Your user name, password, account number and online conversation with friends can be hijacked in such cases.&lt;br /&gt;&lt;br /&gt;Do not simply leave your contact information with unknown party. It is quite common that in a lot of marketing campaign, you will be asked to fill up survey form with personnel information or to drop your name card to stand a chance to win great prizes. You can never be sure how that information will be used against you. If you do not feel comfortable, then don't feel hesitate to say no. Even disclosing simple contact like email can punish you with hundreds of spam mail everyday.&lt;br /&gt;&lt;br /&gt;Friends are not always friend after all. Using internet, people can always get to know new friends through online chat room, instant messenger, and online community website or discussion group. Social engineer may have setup trap and make friend with you long before they ask for anything. Never trust anybody who you do not personally know or met. You may be a good guy, but not everyone is like you.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This article is by no mean a complete description and explanation of social engineering. I have only scratched the surface of social engineering. If you are interested in reading more about social engineering, there are two books which I strongly recommend:&lt;br /&gt;&lt;br /&gt;The Art of Deception by Kevin Mitnick.&lt;br /&gt;The Art of Intrusion by Kevin Mitnick.&lt;br /&gt;&lt;br /&gt;These two books provide a lot of interesting stories, case study on social engineering and a comprehensive list of methods and techniques of how to protect yourself and your company.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-116038029221504360?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/116038029221504360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=116038029221504360' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116038029221504360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116038029221504360'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/10/social-engineering-part-3.html' title='Social Engineering, Part 3'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-116038015872883182</id><published>2006-10-11T10:40:00.000+08:00</published><updated>2007-02-27T21:20:54.006+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Social Engineering, Part 2</title><content type='html'>&lt;h3&gt;Understanding How Attackers Take Advantage of Human Nature&lt;/h3&gt;&lt;br /&gt;&lt;b&gt;Authority&lt;/b&gt;&lt;br /&gt;People have a tendency to comply when a request is made by a person in authority. A person can be convinced to comply with a request if he believes the requestor is a person in authority to make such request. In our society, we have always been told not to question someone who is in authority.&lt;br /&gt;&lt;br /&gt;For example, if a person requesting a piece of information from you and this person claim that he is from the executive office, you will have the tendency to comply without question because you know you should never challenges your bosses.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Liking/ Deceptive Relationship&lt;/b&gt;&lt;br /&gt;People have a tendency to comply when the requestor seems to have similar interests, belief, attitudes and backgrounds as the victim. We always implicitly trust someone who shares similarity with us. We subconsciously believe that people who have similarity with us will also think and behave in a similar way and they are always good guys.&lt;br /&gt;&lt;br /&gt;Deceptive Relationship is sharing information or discuss about a common enemy or problem with the victim making the victim to believe that they are in the same camp.&lt;br /&gt;&lt;br /&gt;For example, when we are talking to someone who seems to share the same interest with us, we have a tendency to let down our defense guard and go further in the conversation with them and reveal more information.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reciprocation&lt;/b&gt;&lt;br /&gt;We may automatically comply with a request when we have been given or promise something of value. When someone has done something for you, you feel an inclination to reciprocate. One of the most effective ways of influence people to do us a favor is by giving some gift or assistance that forms an underlying obligation.&lt;br /&gt;&lt;br /&gt;Very often, we felt reluctant to decline request from someone who has just done us a favor or who has given us a small gift even though in our mind we are uncomfortable of doing so. In our education, we have been taught to remember those who have help us and we should always help back when needed to.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Consistency&lt;/b&gt;&lt;br /&gt;People have the tendency to comply once they have made a public statement or commitment. Once we have promised we will do something, we don't want to appear untrustworthy and will tend to follow through in order to be consistent with our statement or commitment.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Social Validation&lt;/b&gt;&lt;br /&gt;People have the tendency to comply when doing so appears to be inline with others are doing. The actions of others are accepted as validation that the behavior in question is correct.&lt;br /&gt;&lt;br /&gt;When we are in doubt whether to take certain action, we always refer to the peoples surrounding us to find out whether they did the same. Most of the time we will just follow what others did without questioning the validity of our decision.&lt;br /&gt;&lt;br /&gt;When a social engineer is asking for information from a victim, he would mention that what he is asking for is a routine questionnaire and that the victim's peers have also responded to the same set of questionnaires. The victim will then feel no reason to decline since their peers has done it, it must be the right thing to do.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Scarcity&lt;/b&gt;&lt;br /&gt;People have the tendency to comply when it is believed that the object sought is in short supply, or is only available for a short period of time.&lt;br /&gt;&lt;br /&gt;Peoples have natural tendency to take advantage of offers that are made to them such as a free gift if they could just respond to certain request. A social engineer may approach you and offer you a drink voucher if you could just spent five minutes to complete a questionnaire for their survey.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Strong Affect&lt;/b&gt;&lt;br /&gt;Strong Affect plays on the victim's emotion. The attacker can create fear, panic or excitement.&lt;br /&gt;&lt;br /&gt;For example, the attacker will make his request sounds very urgent and stress out his victim so that his victim will panic and reveal the information without careful thinking.&lt;br /&gt;&lt;br /&gt;Another example is to create excitement and surprises by telling the victim he could stand a chance to win a big prize by registering themselves as a member of some community or club.&lt;br /&gt;&lt;br /&gt;The surge of strong emotion will distract the victim ability to evaluate and think logically.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Diffusion of Responsibility&lt;/b&gt;&lt;br /&gt;In this method, the attacker makes the victim to believe that he will not be responsible and liable for his action. It is much easier to get someone to carry out an action if he believes that he does not need to be responsible for his decision.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Moral Duty&lt;/b&gt;&lt;br /&gt;Human feel great and delight when they can do something to help out the others. The social engineer play on this fact to convince his victim he needs that information to help put the others.&lt;br /&gt;&lt;br /&gt;For example, the attacker may ask the victim for his user name and password because he needs to simulate a network login to troubleshoot network problem which has been troubling the victim's coworker.&lt;br /&gt;&lt;br /&gt;Another example would be a social engineer may be you to ask for the phone number of your friend who he has also met before because he has a business opportunity that your friend may be interested in. Of course you would want to help your friend and how often you will think that giving out phone number is a big deal? But the fact is that it is sometimes a big deal. The social engineer can use the phone number to find out about the owner phone billing info or sell the phone number to third party for telemarketing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Other Mean of Social Engineering Attack&lt;/h3&gt;&lt;br /&gt;So far we have seen how social engineering attack can be conducted using physiological and persuasion technique. The other mean of social engineering attack is through a physical aspect (such as presence at workplace, dumpster diving and on-line) and reverse social engineering.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Workplace&lt;/b&gt;&lt;br /&gt;The social engineer will make a physical presence at the workplace or office of his victim or target attack. He will find ways to by pass security check at the entrance. For example, during morning when the crowds get to work, the security can be circumvented due to the vast amount of peoples who are flowing in and out of the building and the security guard may not be able to keep track of all these peoples. A professional social engineer will dress just like what other people surrounding him is dressing so that he doesn't look foreign, walking confidently and pretend to be talking to someone in the crowd while walking into the lift.&lt;br /&gt;&lt;br /&gt;Another way will be that the social engineer pretend that he has forgot his badge, but he will say something to show that he is familiar with the place and the people around it to make the security guard to believe that he work there.&lt;br /&gt;&lt;br /&gt;Once the social engineer gets in, he can then freely move within the building to find the information he need.&lt;br /&gt;&lt;br /&gt;Although this looks like movie trick, but it does work in real life.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dumpster Diving&lt;/b&gt;&lt;br /&gt;Dumpster diving is also know as trashing. This involve the searching the company dumpster to look for useful information and this effort usually pay off. How often do we ever think of the value of the documents that we throw into the dump bin? Something that seems to have no value to us can mean something else to other people.&lt;br /&gt;&lt;br /&gt;Social engineer can find out about contacts of person from address book, software and hardware vulnerabilities from source code print out, people with specific position and authority from the organization hierarchy chart, company policy about business operation guide. This information will give the attacker a great deal of knowledge how he should plan his next step.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;On-line&lt;/b&gt;&lt;br /&gt;Social engineer can find out vast variety of information from on-line websites. Such information may include company product and services information, executive profiles, events calendar and business partners and customers. The attacker can then use this information to gain knowledge of their victim and launch attack against them.&lt;br /&gt;&lt;br /&gt;Other source of on-line source may include search engine, on-line chat rooms, news group and discussion room. Search engine reveal a lot of links to a particular topic of interest. In newsgroup where peoples are posting question to source for help for their problem, they may accidentally include sensitive information such as user name, password, and system configuration info in their posted question.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reverse Social Engineering&lt;/b&gt;&lt;br /&gt;This is when the hacker creates a problematic situation for the victim and makes himself available to help fix the problem.&lt;br /&gt;&lt;br /&gt;Consider the following phone conversation:&lt;br /&gt;&lt;br /&gt;Hacker : "I am Bob from IT department. Is it Joe speaking?"&lt;br /&gt;Victim : "Yes. How can I help you?"&lt;br /&gt;Hacker : "Hi, Joe. Other users has reported problem with their network connectivity. Are you having any problem with your network?"&lt;br /&gt;Victim : "Everything seems to be fine."&lt;br /&gt;Hacker : "That sounds good. But just in case you have any problem, please call me immediately so that I can fix it for you. You can call me at this number - xxxxxxx"&lt;br /&gt;Victim : "Sure. Thanks. Bye"&lt;br /&gt;&lt;br /&gt;Now, the attacker will proceed to create the problem and wait for the victim to call for help. Once he solves the problem for the victim, the victim will be thankful to him and the attacker will gain trust and confidence from the victim. Now the attacker can proceed to exploit the trust to extract valuable information from the victim.&lt;br /&gt;&lt;br /&gt;However, reverse social engineering is more complex because it requires the hacker to gain access to the victim's network and computer ahead of time to create the problem but it is not impossible.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-116038015872883182?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/116038015872883182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=116038015872883182' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116038015872883182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116038015872883182'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/10/social-engineering-part-2.html' title='Social Engineering, Part 2'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-116037888070555019</id><published>2006-10-09T15:27:00.000+08:00</published><updated>2007-02-27T21:21:07.930+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Social Engineering, Part 1</title><content type='html'>&lt;h3&gt;What is Social Engineering&lt;/h3&gt;&lt;br /&gt;Day to day in our life, we talk to peoples whether it is face to face, on the phone, or some other form of communication. We talk to peoples whether they are people who we know or strangers. In all our interaction with peoples, we have been giving out information to third party, whether it is intended or unintended.&lt;br /&gt;We as a human being has the natural tendency to be helpful, have sympathy for those unfortunate and always try to be a team player.&lt;br /&gt;&lt;br /&gt;Social engineering played on these attributes to break through human defense. Social engineer take advantage of these human natures to get people into complies with them.&lt;br /&gt;&lt;br /&gt;Social engineering is 'The art and science of getting people to comply with your wishes'. It makes use of human intelligence to manipulate human in giving out their secret information. It is a psychological trick. The attacker's goal is to obtain information that will allow him/her to gain unauthorized access to a valued system and the information that resides on that system. It could be a computer information system or private information of someone else.&lt;br /&gt;&lt;br /&gt;During the course of launching a social engineering attack, the attacker may use little or no technology aids at all in accomplishing his goal. Social engineering methods depend on people skills rather than technical skills, since they exploit human nature rather than software or hardware vulnerabilities.&lt;br /&gt;&lt;br /&gt;Common ploys include pretending to be an organization executive or member of the IT staff, a fellow worker, or a member of an outside organization, such as a company vendor, supplier or consultant.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Why Social engineering&lt;/h3&gt;&lt;br /&gt;As security technologies evolve to become more sophisticated, making it increasingly more difficult to exploit technical vulnerabilities, attackers will turn to exploiting the human element. Cracking the human firewall is often easier and involves lower risk if done carefully. For example, password encryption algorithm today is sophisticated enough that it is almost practically infeasible to crack a password using a brute force attack. Even with the fastest computer we can get today, it might take hundreds or more years to break a password. It is just much simpler for the attacker to pose as a helpdesk or IT employee and asking for it.&lt;br /&gt;&lt;br /&gt;Social engineers rely on the fact that people are not aware of the value of the information they possess and are careless about protecting it. How many times have we given out personal information such as credit card number, account number, billing information to party who claim they are from credit card company, phone company, your insurance agent and so on. How many times when you give out this information, you spend even a second to think through whether the caller is really who they claim to be, what are the value of information that you are giving out and why those people need those information. Do you ever bother to verify their identity?&lt;br /&gt;&lt;br /&gt;Human factor is always the security's weakest link. This is due to our uneducated, ignorance and misconception of security. We have never been taught in school how to protect our self from information theft, how we should value information and how to protect privacy.&lt;br /&gt;&lt;br /&gt;We could have installed the most sophisticated door lock in our house. But if we do not know how to use the lock properly, if we do not know how to deal with a stranger who knocks on our door, if we do not ensure our surrounding is safe when we open the door, we are still vulnerable of letting the stranger into our house. Human factor is often the most overlook element in the security chain. Social engineer understands this gap in security chain. They have always take advantage of our desire to be helpful, friendly, sympathy and ignorance to accomplish their goal. Thus, social engineering is the most difficult form of attack to defend against.&lt;br /&gt;&lt;br /&gt;Social engineering is not just limited to computer crime. It is generally a technique used by people who are interested to gain access to information which normally they cannot get access to or what most peoples think is impossible to obtain.&lt;br /&gt;&lt;br /&gt;For example, private investigator may use social engineering technique to obtain private information such as financial status about his target under investigation. He could pretend to be his target under investigation, call the bank, tell the bank he need a bank statement to apply for credit card and ask the bank to fax over his bank statement.&lt;br /&gt;&lt;br /&gt;Another example is commercial spy who want to steal confidential product information from his competitor. The spy could pretend to be consultant or someone in the partner company who help in the development of the product and convince the employees in the target company to reveal important information about the competing product under development. By doing so, the commercial spy would gain a step ahead of his competition and well prepared to counter the competition.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;How Social Engineering Work&lt;/h3&gt;&lt;br /&gt;It is often no surprise that even after a victim has been lulled into giving out sensitive information to the attacker, he still has no idea he had felled into a social engineering attack. A successful social engineering attack will always leave their victim unsurprised and unaware of what happen.&lt;br /&gt;&lt;br /&gt;Social engineering attack is well organized, planned and thought through. A professional social engineer will always plan out his attack well before he launches it. He always knows his stuff well.&lt;br /&gt;&lt;br /&gt;Here are the general cycles of a typical social engineering attacks:&lt;br /&gt;&lt;br /&gt;1. &lt;b&gt;Setting the Stage&lt;/b&gt;&lt;br /&gt;The attacker will identify what he wants to accomplish and how he want to accomplish it.&lt;br /&gt;&lt;br /&gt;2. &lt;b&gt;Research&lt;/b&gt;&lt;br /&gt;The attacker will start by doing his home work to find out key information such as:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Name of some key persons who he can use and pretend to be. It is even more useful if he can find out the name of person who has high authority in the setup.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Jargon or technical terms which are used in the specific industry or the company he planned to attack. Ability to use context specific term in conversation will make people to believe that the attacker does come from the same background or is part of them.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Company background and product information, policy and business process. Understanding the company operation and policy will help the attacker to identify the target weakness and how to exploit it. The knowledge is also useful in helping the attacker to convince their victim that he is part of that environment.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Victim background and habits. Understanding the victim's background will give the attacker an effective way to engage the victim in a seemly comfortable and enjoyable conversation and paving a better way to develop and gain trust.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Knowing all these information is important at a later stage to develop trust relationship with the victim. We always implicitly trust someone who can mention specific terms which we always use in our job, know about our background or mention some of the names that we know of.&lt;br /&gt;&lt;br /&gt;3. &lt;b&gt;Developing Trust&lt;/b&gt;&lt;br /&gt;After gathering useful information, the attacker will approach the victim. The attacker will start a conversation and using the information he gathered, he will attempt to develop trust relationship with his target. The attacker could have get right into the point and ask for the relevant information that he need. However, doing so will be too suspicious and could ring the alarm bell on the victim. Instead, the attacker will start the conversation in a casual manner, pretend to be friendly and gradually progress. Along the conversation, the attacker will pick up different sign such as the victim hesitation in respond to the conversation or the victim appears to be cooperative, helpful or courteous.&lt;br /&gt;&lt;br /&gt;It is human nature that we will implicitly trust someone who claims to be from authority, someone who seems to know a lot of us, about our environment, what we are doing and perhaps share the same interest. We also tend to trust someone who sounds to be helpful, friendly and courteous. Social engineer knows this well and his research in the previous stage is very important for his success. At this stage, his goal is to gain trust, convince his victim and make the victim feel comfortable with him.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. &lt;b&gt;Exploiting Trust&lt;/b&gt;&lt;br /&gt;Once the trust is established, the attacker will ask questions which will gain him valuable information, or he could have asked the victim to perform an action on his behalf. Using a more advance techniques, the attacker could even setup a situation where the victim will ask him for help. This technique is call reverse social engineering.&lt;br /&gt;&lt;br /&gt;When the attacker feels that the victim is comfortable with him and is ready to reveal information, he will proceed to ask for information he is interested in. A good social engineer knows that if he moves in too fast, he might be caught suspicious. He knows he needs a lot of patience. He continues his conversation with seemingly innocent subjects, and in between, he will ask question which will gain him the information he need. He then gauges the respond of the victim. If the victim still sounds cooperative, he will continue with other questions he has in his list. If the victim demonstrates hesitation, the attacker might divert the conversation to some other topics before coming back again with his next question, or he might gracefully stop the conversation and move on with his next victim.&lt;br /&gt;&lt;br /&gt;A good social engineer understands that in gaining the information that he need, patience and timing is very important. If he gets in with the question too early in the conversation before the victim is ready, the victim will be hesitate to answer and his action could be suspicious. If he end the conversation right after he obtain the information, the victim will always remember what he has ask for and might also raise suspicious. A smart social engineer is always sensitive to his victim and knows when he should slot in his question in the conversation. Once he has got all the information he need, he will follow with a couple more casual topics and questions before he end the conversation. This step is important because most of the time, people only remember what happen at the start and at the end. They might not remember well what happen in between. By using this technique, the victim might not remember well what the attacker has asked him for.&lt;br /&gt;&lt;br /&gt;The process of developing trust, exploiting trust and obtaining the information could be as simple as a few minutes of conversation with a single victim. Or it could also be a situation where the attacker has to establish contact with a few victims to extract bits and pieces of information from each of them individually. The situation is largely depends on what actually happen during the contact and how cooperative the victim is. It also depends on the type of information to be obtained.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. &lt;b&gt;Utilize Information&lt;/b&gt;&lt;br /&gt;Once the information is obtained, the attacker will use the information he obtained to accomplish his final goal. If the information obtain is only to help to get one step closer to the final goal, the attacker will return to the earlier cycle until he reach his final goal.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In this part one of the article, we have introduce ourselves to what is social engineering, why hack choose to use such as attack approach, and what is the typical life cycle of social engineering attack.&lt;br /&gt;&lt;br /&gt;In the next article, we will look into why social engineering attack work after all, what are the other means of social engineering attack and how to identify and combat against them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-116037888070555019?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/116037888070555019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=116037888070555019' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116037888070555019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/116037888070555019'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/10/social-engineering-part-1_116037888070555019.html' title='Social Engineering, Part 1'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-115443176299481374</id><published>2006-08-01T19:26:00.000+08:00</published><updated>2007-02-27T22:00:12.744+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Design Fallacy - Lesson 1</title><content type='html'>&lt;h2&gt;Design and deliver only What you Need&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Recently I was writing a WSS (Windows Sharepoint Services) utility to help my user to eliminate some tedious repeatative.&lt;br /&gt;&lt;br /&gt;Due to the access restriction for documents in document library, the sys admin need to customize the security setting for certain document library in the wss site. This is quite a tedious task as new site is created quite often and each site has a few document library. It takes many mouse clicks to accomplish the process.&lt;br /&gt;&lt;br /&gt;I figure that it is possible to write a utility to automate this series of tasks using the WSS SDK. As i am writing this utility as a personal favor, there are not proper requirements, no time constraint and no limit to features.&lt;br /&gt;&lt;br /&gt;Halfway through development, i was kind of stuck thinking what is the best way to present the UI and I realize i make a design philosophical mistake that many people tend to make as well.&lt;br /&gt;&lt;br /&gt;The problem here is overdesign and attempt to go beyond the requirements.&lt;br /&gt;The admin only need three functions:&lt;br /&gt;&lt;OL&gt;&lt;br /&gt;&lt;LI&gt;Add a predefined list of domain users into the new site.&lt;br /&gt;&lt;LI&gt;Remove the default groups from the document library.&lt;br /&gt;&lt;LI&gt;Add the new groups/users into the document library with specific permission.&lt;br /&gt;&lt;/OL&gt;&lt;br /&gt;&lt;br /&gt;The admin only need a simple car and I was on my way to build a car with turbo engine with backfire. I was trying to build a general document library administration&lt;br /&gt;tool instead which is way more comprehensive.&lt;br /&gt;&lt;br /&gt;Obviously, my utility application will be able what the sys admin want to do and even&lt;br /&gt;more. But when I sit down and think of the usability issue, I quickly realize it was too ambitious, too general and too much functionalities.&lt;br /&gt;&lt;br /&gt;Having more is not a bad thing, but it is not always a good thing either. Having more functionality than necessary mean the user need to have more interaction &lt;br /&gt;with the application. &lt;br /&gt;&lt;br /&gt;So, the problem is :&lt;br /&gt;&lt;OL&gt;&lt;br /&gt;&lt;LI&gt;The more functionality the application have, the more interaction the user need to do.&lt;br /&gt;&lt;LI&gt;The more interaction the user need to do, the more decision the user need to make and the more discoveries the user need to make.&lt;br /&gt;&lt;LI&gt;The more decision the user need to make, the lower the productivity the user become.&lt;br /&gt;&lt;LI&gt;The more discoveries the user need to make, the more distraction the user is going to have and the less usable the application become.&lt;br /&gt;&lt;/OL&gt;&lt;br /&gt;&lt;br /&gt;Eventually the user will find the application too complicated for simple purpose and revert to the old ways of doing things. Then all your hard work will go into drain.&lt;br /&gt;&lt;br /&gt;The best application is not one with many features, rather it is one with the function that solve the user's problem at heart efficiently.&lt;br /&gt;&lt;br /&gt;By focusing only on the absolute requirements and nothing more:&lt;br /&gt;&lt;OL&gt;&lt;br /&gt;&lt;LI&gt;You will need less development time which will drive down cost.&lt;br /&gt;&lt;LI&gt;Simple application with less but important functions.&lt;br /&gt;&lt;LI&gt;You will have a simple application which require minimal learning curve.&lt;br /&gt;&lt;LI&gt;User is more productive because the application does not require them to make decision.&lt;br /&gt;&lt;/OL&gt;&lt;br /&gt;So, I went back to design the application just to have only that three functions and nothing more. It took me only half a night to complete the application and ready to ship by the next day. And most important, the application is way much easier to use.&lt;br /&gt;&lt;br /&gt;The lesson here, focus only on core requirements and nothing else. Don't make your life and your user's life complicated. Just because you can do something, doesn't mean you have to do it. You don't show value by delivering more functions, rather by showing user you understand their real problem and solve it in the most elegant way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-115443176299481374?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/115443176299481374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=115443176299481374' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/115443176299481374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/115443176299481374'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/08/design-fallacy-lesson-1.html' title='Design Fallacy - Lesson 1'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-115215248707885309</id><published>2006-07-06T10:05:00.000+08:00</published><updated>2007-02-27T20:56:58.131+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>Project2k3 : Gantt Chart Time Scale</title><content type='html'>I got an unusual feature enquiry from some one today. The question was :&lt;br /&gt;&lt;br /&gt;When project plan displayed gantt chart from Microsoft Project Professional 2003, we can control a total of 3-tier of timeline. For example, tier-1 can display "Year" and tier-2 can display "Month", so, when you see the gantt chart, it is displayed "Year-Month" structure throughout the whole gantt chart.&lt;br /&gt;&lt;br /&gt;Now the customer actually want to see that "Year-Month" structure for a period of time AND at the same gantt chart, they want to see "Year" structure (without revealing the month column) for the remaining period. Can it be done?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The simple answer is NO, it cannot be done.&lt;br /&gt;&lt;br /&gt;This is an unusual feature enquiry , so far I haven't see any planning and scheduling tools that has this feature. I have use MS Project, Primavera and OpenPlan(while cover almost 80 to 90% of the planning and scheduling tool market) and none of these tool have that feature.&lt;br /&gt;&lt;br /&gt;In my opinion, if it does allow you to do that, I think it will cause more inconsistency and confusion than doing anything good. Technically, it is also difficult and infeasible to implement this feature.&lt;br /&gt;&lt;br /&gt;Just imagine the following scenario:&lt;br /&gt;You want to display "Year-Month" for activities between 1-Jan-2006 to 31-Dec-2006. Then for activities after 31-Dec-2006, you only want to display "Year". Now, you have a few if not a lot of activities that span through this time period, EG : you have activity or WBS that start before 31-Dec-2006 and finish after 1-Jan-2007. How you think the gantt chart should now be draw ? Half in "Year-Month" and the other half in "Year"? If so, is it going to be very confusing ?&lt;br /&gt;&lt;br /&gt;If the tool force you to have a clear cut of dates so that your activities does not overlap into the two time period, then you are going to have another problem. Now you have to break your overlapping activites into two separate activites each with no overlapping time period but it essentialy represent the same unit of task. This will make your planning much more harder, abnormal and of course result in a very confusing schedule.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If your objective is not to look at activities that are after certain time period, then just use a filter to filter out those activities that are not within the time period of your interest.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-115215248707885309?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/115215248707885309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=115215248707885309' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/115215248707885309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/115215248707885309'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/07/project2k3-gantt-chart-time-scale.html' title='Project2k3 : Gantt Chart Time Scale'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-115215137804884376</id><published>2006-07-06T09:55:00.000+08:00</published><updated>2007-02-27T20:57:02.403+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>PS2k3 : Project Server Active Directory Synchronization</title><content type='html'>I posted a document painting a few scenarios when Active Directory synchronization will work with Project Server and when it will not.&lt;br /&gt;&lt;br /&gt;The URL is : &lt;a href="http://workspaces.gotdotnet.com/jyps" target="_blank"&gt;http://workspaces.gotdotnet.com/jyps&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-115215137804884376?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/115215137804884376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=115215137804884376' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/115215137804884376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/115215137804884376'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/07/ps2k3-project-server-active-directory.html' title='PS2k3 : Project Server Active Directory Synchronization'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114822662929944033</id><published>2006-05-21T23:49:00.000+08:00</published><updated>2007-02-27T20:57:06.058+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>Project2k3: Highlight completed task</title><content type='html'>I got a question on how to highlight the row of a completed task in MS Project to Red color.&lt;br /&gt;&lt;br /&gt;To accomplish this, you need to write a VBA macro and run this macro after you finish updating your project.&lt;br /&gt;&lt;br /&gt;Here is the macro that does the work.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;Sub MarkCompletedTask()&lt;br /&gt;    Dim startRow As Integer&lt;br /&gt;    Dim tsk As task&lt;br /&gt;    Dim today As Date&lt;br /&gt;   &lt;br /&gt;    startRow = 1&lt;br /&gt;    today = Date&lt;br /&gt;   &lt;br /&gt;    SelectRow Row:=startRow, RowRelative:=False&lt;br /&gt;    Set tsk = ActiveCell.task&lt;br /&gt;    If tsk Is Nothing Then&lt;br /&gt;        Exit Sub&lt;br /&gt;    End If&lt;br /&gt;   &lt;br /&gt;    Application.ScreenUpdating = False&lt;br /&gt;   &lt;br /&gt;    Do While True&lt;br /&gt;        If tsk.PercentComplete = 100 Then&lt;br /&gt;            Font Color:=1&lt;br /&gt;        Else&lt;br /&gt;            Font Color:=16&lt;br /&gt;        End If&lt;br /&gt;&lt;br /&gt;        startRow = startRow + 1&lt;br /&gt;        SelectRow Row:=startRow, RowRelative:=False&lt;br /&gt;       &lt;br /&gt;        Set tsk = ActiveCell.task&lt;br /&gt;        If tsk Is Nothing Then&lt;br /&gt;            Exit Do&lt;br /&gt;        End If&lt;br /&gt;    Loop&lt;br /&gt;   &lt;br /&gt;    Application.ScreenUpdating = True&lt;br /&gt;End Sub&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114822662929944033?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114822662929944033/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114822662929944033' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114822662929944033'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114822662929944033'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/05/project2k3-highlight-completed-task.html' title='Project2k3: Highlight completed task'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114734853025148102</id><published>2006-05-11T19:53:00.000+08:00</published><updated>2007-02-27T20:57:30.247+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>PS2003 : Save all Server Projects locally</title><content type='html'>How to automate the process of dumping all projects in Project Server database into MPP file.&lt;br /&gt;Here is the VBA macro that does that. Paste the following macro into MS Project's VBA editor and run it.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;Sub ExportAllProjects()&lt;br /&gt;    Dim conn As ADODB.Connection&lt;br /&gt;    Dim connStr As String&lt;br /&gt;    Dim rs As ADODB.Recordset&lt;br /&gt;    Dim sql As String&lt;br /&gt;    Dim projName As String&lt;br /&gt;    Dim savePath As String&lt;br /&gt;    Dim outFile As String&lt;br /&gt;   &lt;br /&gt;    savePath = "c:\projectfiles\"&lt;br /&gt;   &lt;br /&gt;    connStr = "provider=sqloledb; data source=db_server_name; "&lt;br /&gt;    connStr = connStr &amp;amp; quot;initial catalog=projectserver; "&lt;br /&gt;    connStr = connStr &amp; user id=sa; password=password"&lt;br /&gt;   &lt;br /&gt;    sql = "SELECT PROJ_PROJECT "&lt;br /&gt;    sql = sql &amp;amp; " From MSP_PROJECTS "&lt;br /&gt;    sql = sql &amp;amp; " WHERE PROJ_TYPE = 0 "&lt;br /&gt;    sql = sql &amp;amp; " AND PROJ_ADMINPROJECT=0 "&lt;br /&gt;    sql = sql &amp;amp; " AND PROJ_VERSION='Published' "&lt;br /&gt;&lt;br /&gt;    Set conn = New ADODB.Connection&lt;br /&gt;    conn.Open connStr&lt;br /&gt;   &lt;br /&gt;    Set rs = conn.Execute(sql)&lt;br /&gt;&lt;br /&gt;   &lt;br /&gt;    While Not rs.EOF&lt;br /&gt;        projName = rs("PROJ_PROJECT") &amp;amp; ".Published"&lt;br /&gt;        outFile = Replace(rs("PROJ_PROJECT"), "&amp;lt;&amp;gt;\", "") &amp;amp; ".mpp"&lt;br /&gt;       &lt;br /&gt;        FileOpen Name:=projName&lt;br /&gt;        FileSaveAs Name:=savePath &amp;amp; outFile, FormatID:="MSProject.MPP"&lt;br /&gt;        FileClose&lt;br /&gt;        rs.MoveNext&lt;br /&gt;    Wend&lt;br /&gt;   &lt;br /&gt;    rs.Close&lt;br /&gt;    Set rs = Nothing&lt;br /&gt;    conn.Close&lt;br /&gt;    Set conn = Nothing&lt;br /&gt;   &lt;br /&gt;    MsgBox "done"&lt;br /&gt;   &lt;br /&gt;    Exit Sub&lt;br /&gt;   &lt;br /&gt;Err_Handler:&lt;br /&gt;    MsgBox Err.Description&lt;br /&gt;    If rs.State = adStateOpen Then rs.Close&lt;br /&gt;    If conn.State = adStateOpen Then conn.Close&lt;br /&gt;   &lt;br /&gt;    Set rs = Nothing&lt;br /&gt;    Set conn = Nothing&lt;br /&gt;End Sub&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114734853025148102?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114734853025148102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114734853025148102' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114734853025148102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114734853025148102'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/05/ps2003-save-all-server-projects.html' title='PS2003 : Save all Server Projects locally'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114665975311879003</id><published>2006-05-03T20:34:00.000+08:00</published><updated>2007-02-27T20:57:34.651+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>PS2003: Update Other Fields in Timesheet view.</title><content type='html'>In the Web Access Timesheet View (Accessed via the Tasks top navigation bar), team member by default can only update the % Work Complete and Remaining Work column.&lt;br /&gt;&lt;br /&gt;It is quite often that people ask whether they can update other field. One of the common requests is for team member to update Actual Start date.&lt;br /&gt;&lt;br /&gt;Here is how you do it...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://workspaces.gotdotnet.com/jyps" target="_blank"&gt;http://workspaces.gotdotnet.com/jyps&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114665975311879003?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114665975311879003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114665975311879003' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114665975311879003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114665975311879003'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/05/ps2003-update-other-fields-in.html' title='PS2003: Update Other Fields in Timesheet view.'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114309414113684489</id><published>2006-03-23T14:06:00.000+08:00</published><updated>2007-02-27T20:57:41.263+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sharepoint'/><title type='text'>WSS : Multiple Templates DocLib v2.0</title><content type='html'>I have fix the security issue when running as non-admin user in MultiTemplate DocLib and re-relase it as v2.0&lt;br /&gt;&lt;br /&gt;&lt;a href="http://workspaces.gotdotnet.com/jywss" target="_blank"&gt;http://workspaces.gotdotnet.com/jywss&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114309414113684489?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114309414113684489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114309414113684489' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114309414113684489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114309414113684489'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/03/wss-multiple-templates-doclib-v20.html' title='WSS : Multiple Templates DocLib v2.0'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114300382109010169</id><published>2006-03-22T12:52:00.000+08:00</published><updated>2007-02-27T20:58:07.909+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sharepoint'/><title type='text'>Security Issue with MultiTemplate DocLib</title><content type='html'>The reason for the pull back of v1.1 is that as I tested the doc lib with a non-admin user, an authentication problem arise.&lt;br /&gt;&lt;br /&gt;My initial idea is to store all the local templates in the Forms folder. However, I found out that non-admin user will not be able to access files in the Forms folder. I found a workaround for this. I just create another folder(named documentTemplate) in the doc lib and store those templates in this folder. My code will then read all those templates from this folder.&lt;br /&gt;&lt;br /&gt;As i continue testing, I found another security issue. When a non-admin user create a new document from a template stored in global template (under _layouts/documentTemplate), the user get a authentication dialog. Word, Excel and Powerpoint handle this differently. In Word and Excel, if you click Cancel in the dialog, the template that you select will still open. In Powerpoint, however, the template will not be open. This issue also happen in v1.0 which I have not tested with non-admin user.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am still in the middle of finding out why there is an authentication dialog. Will update once I found the solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114300382109010169?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114300382109010169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114300382109010169' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114300382109010169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114300382109010169'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/03/security-issue-with-multitemplate.html' title='Security Issue with MultiTemplate DocLib'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114295629720312065</id><published>2006-03-21T23:49:00.000+08:00</published><updated>2007-02-27T20:58:13.645+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sharepoint'/><title type='text'>WSS : Multiple Templates DocLib v1.1</title><content type='html'>&lt;b&gt;Note : MultiTemplate DocLib v1.1 has been pulled back due to some issues run running as non-admin.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have posted a new release of my Multiple Templates DocLib on GotDotNet workspace.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What is new is v1.1?&lt;/b&gt;&lt;br /&gt;Added support to retrive document templates from the document library &lt;i&gt;Forms&lt;/i&gt; folder.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://workspaces.gotdotnet.com/jywss" target="_blank"&gt;http://workspaces.gotdotnet.com/jywss&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114295629720312065?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114295629720312065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114295629720312065' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114295629720312065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114295629720312065'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/03/wss-multiple-templates-doclib-v11.html' title='WSS : Multiple Templates DocLib v1.1'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114189193355507059</id><published>2006-03-09T16:09:00.000+08:00</published><updated>2007-02-27T20:58:17.579+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>PS2003 : Creating new ProjectServer site with WSS integration.</title><content type='html'>If you are creating the second ProjectServer site using the EditSite tool and want to integrate with WSS, you need to change the Server Intranet Address in ProjectServer after creating the site in order for it to link correctly.&lt;br /&gt;&lt;br /&gt;Take the following scenario.&lt;br /&gt;&lt;br /&gt;I installed ProjectServer and WSS.&lt;br /&gt;&lt;br /&gt;My ProjectServer URL is http://servername/ProjectServer and the WSS URL is http://servername:800.&lt;br /&gt;&lt;br /&gt;Now I want to create another ProjectServer site and WSS site and integrate the two together.&lt;br /&gt;&lt;br /&gt;The easist way for me to start is to backup the existing ProjectServer database and restore it as another database(EG: ProjectServer2).&lt;br /&gt;&lt;br /&gt;Next, I create and extend another WSS site to run on port 850. so the WSS URL will be http://servername:850.&lt;br /&gt;&lt;br /&gt;Now I use the EditSite tool to create another ProjectServer site. The URL for this PS site will be http://servername/projectServer2. When I create the site, I specify I want to setup WSS and ProjectServer integration.&lt;br /&gt;&lt;br /&gt;If your didn't make any mistake, everything will work just fine as of this stage.&lt;br /&gt;&lt;br /&gt;Now, I publish a new project to ProjectServer2 and automatically a new WSS project site will be created. Say for example, the URL for the project site is http://servername:850/sites/ProjectServer2_201.&lt;br /&gt;&lt;br /&gt;Then I go to the project site and create a new issue. In the new issue page, if I click on the 'Select project tasks that are impacted by this issue' link or any of those related link at the bottom, you will notice Task Dialog does not show the correct task for the project. It either show the task for another project or it will be disabled.&lt;br /&gt;&lt;br /&gt;When you save the issue, you will also notice there is no issue icon for that project in the Web Access Project Center. This show that the issue is not link back to the project.&lt;br /&gt;&lt;br /&gt;After some tracing and hacking, I found out why it show the wrong project task. If your project ID is 201, the task dialog will actually retrieve tasks for project which has ID 201 from ProjectServer(the default one) and not ProjectServer2. If it cannot find a project with ID 201 in ProjectServer, it will disable the dialog.&lt;br /&gt;&lt;br /&gt;Here come the question, why is it so?&lt;br /&gt;&lt;br /&gt;When ProjectServer create a new WSS site for a project, it will insert the ProjectServer intranet URL into the site's SPWeb property. The intranet URL is used by the Task dialog to retrieve the project task. The intranet URL is stored in the database. So when I restore the ProjectServer database to ProjectServer2, it will&lt;br /&gt;carry the orginial value which is 'http://servername/projectserver' in ProjectServer2 database.&lt;br /&gt;&lt;br /&gt;To correct this, after you create the new ProjectServer site, you need to logon to the Web Access (EG: http://servername/projectserver2), go to Admin -&gt; Server Configuration. Then change the Server Intranet Address to 'http://servername/projectserver2' (or whatever your project server url).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114189193355507059?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114189193355507059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114189193355507059' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114189193355507059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114189193355507059'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/03/ps2003-creating-new-projectserver-site.html' title='PS2003 : Creating new ProjectServer site with WSS integration.'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114187694870378041</id><published>2006-03-09T12:00:00.000+08:00</published><updated>2007-02-27T20:59:29.986+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='aspnet'/><title type='text'>ASPNET 2.0 : Finding control in WebForm that use MasterPage</title><content type='html'>When you try to lookup a control by passing a control ID to the &lt;i&gt;FindControl&lt;/i&gt; method,&lt;br /&gt;it work a little bit differenly depend on whether your WebForm page use MasterPage or not.&lt;br /&gt;&lt;br /&gt;If your are not using MasterPage, the following code will simple return a reference to the WebControl with ID "TextBox1".&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;        Control c = FindControl("TextBox1");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;However, if your WebForm use MasterPage, the above code won't work. You have to get a reference to the ContentPlaceHolder which contain your control and then call FindControl() on the ContentPlaceHolder object.&lt;br /&gt;&lt;br /&gt;The following code show hot to do it. Create the following MasterPage and call it MasterPage.master&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;&amp;lt;%@ Master Language="C#"&lt;br /&gt;   AutoEventWireup="true"&lt;br /&gt;   CodeFile="MasterPage.master.cs"&lt;br /&gt;   Inherits="MasterPage" %&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC&lt;br /&gt;  "-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;br /&gt;  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;html xmlns="http://www.w3.org/1999/xhtml" &amp;gt;&lt;br /&gt;&amp;lt;head runat="server"&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Untitled Page&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;form id="form1" runat="server"&amp;gt;&lt;br /&gt;    &amp;lt;div&amp;gt;&lt;br /&gt;        &amp;lt;asp:contentplaceholder id="ContentPlaceHolder1"&lt;br /&gt;        runat="server"&amp;gt;&lt;br /&gt;        &amp;lt;/asp:contentplaceholder&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, create a WebForm that use MasterPage.master as master page and insert a TextBox into the WebForm. Give the TextBox an ID "txtFindControl".&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;&amp;lt;%@ Page Language="C#"&lt;br /&gt;    AutoEventWireup="true"&lt;br /&gt;    CodeFile="MasterPageJustFindControl.aspx.cs"&lt;br /&gt;    Inherits="MasterPageJustFindControl"&lt;br /&gt;    MasterPageFile="~/MasterPage.master" %&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;asp:Content ID="Content1"&lt;br /&gt;             ContentPlaceHolderID="ContentPlaceHolder1"&lt;br /&gt;             Runat="Server"&amp;gt;&lt;br /&gt;     &amp;lt;asp:TextBox ID="txtFindControl" runat="server"&amp;gt;&lt;br /&gt;     &amp;lt;/asp:TextBox&amp;gt;   &lt;br /&gt;&amp;lt;/asp:Content&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next, go to the code behind file of the web form and insert the following code:&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;public partial class MasterPageJustFindControl : System.Web.UI.Page&lt;br /&gt;{&lt;br /&gt;    protected void Page_Load(object sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        JustFindControl();&lt;br /&gt;        MasterPageFindControl();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void JustFindControl()&lt;br /&gt;    {&lt;br /&gt;        Control c = FindControl("txtFindControl");&lt;br /&gt;&lt;br /&gt;        if (c is WebControl)&lt;br /&gt;        {&lt;br /&gt;            Response.Write("&amp;lt;BR&amp;gt;JustFindControl : WebControl found&amp;lt;BR&amp;gt;");&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            Response.Write("&amp;lt;BR&amp;gt;JustFindControl : NOT found&amp;lt;BR&amp;gt;");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void MasterPageFindControl()&lt;br /&gt;    {&lt;br /&gt;        ContentPlaceHolder cpholder = (ContentPlaceHolder)Master.&lt;br /&gt;             FindControl("ContentPlaceHolder1");&lt;br /&gt;&lt;br /&gt;        Control c = cpholder.FindControl("txtFindControl");&lt;br /&gt;&lt;br /&gt;        if (c is WebControl)&lt;br /&gt;        {&lt;br /&gt;            Response.Write("&amp;lt;BR&amp;gt;MasterPageFindControl : WebControl found&amp;lt;BR&amp;gt;");&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            Response.Write("&amp;lt;BR&amp;gt;MasterPageFindControl : NOT found&amp;lt;BR&amp;gt;");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When you run the above code, the output should be&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;JustFindControl : NOT found&lt;br /&gt;&lt;br /&gt;MasterPageFindControl : WebControl found&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That approach make some sense though. Because a MasterPage can have multiple ContentPlaceHolder(s) which host different WebForm. Each of those WebForm could have controls with the same ID. So, I think this is a way to isolate the controls from being having ID conflict.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114187694870378041?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114187694870378041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114187694870378041' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114187694870378041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114187694870378041'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/03/aspnet-20-finding-control-in-webform.html' title='ASPNET 2.0 : Finding control in WebForm that use MasterPage'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114123631600630055</id><published>2006-03-02T02:02:00.000+08:00</published><updated>2007-02-27T20:59:34.613+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sharepoint'/><title type='text'>WSS : Security Exception when Upload File using WSS SDK</title><content type='html'>I keep hitting an exception when I use the WSS SDK to upload a document to a document library in my WSS app. The error message read&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;The security validation for this page is invalid.&lt;br /&gt;Click Back in your Web browser, refresh the page,&lt;br /&gt;and try your operation again.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After some googling, the solution is you have to set the &lt;i&gt;AllowUnsafeUpdates &lt;/i&gt;property of &lt;i&gt;SPSite&lt;/i&gt; and &lt;i&gt;SPWeb&lt;/i&gt; object to true before you upload the file. The code look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;using System.IO;&lt;br /&gt;&lt;br /&gt;private void btnUpload_Click(object sender, System.EventArgs e)&lt;br /&gt;{&lt;br /&gt;    string targetSite = "http://wssserver/sites/myteamsite";&lt;br /&gt;    string docLib = "my doc lib";&lt;br /&gt;    byte[] contents = null;&lt;br /&gt;&lt;br /&gt;    string saveAsFile = Path.GetFileName(FileUpload.PostedFile.FileName);&lt;br /&gt;    Stream stream  = FileUpload.PostedFile.InputStream;&lt;br /&gt;&lt;br /&gt;    contents = new byte[(int)stream.Length];&lt;br /&gt;    stream.Read(contents, 0, (int)stream.Length);&lt;br /&gt;    stream.Close();&lt;br /&gt;&lt;br /&gt;    SPSite site = new SPSite(targetSite);&lt;br /&gt;    SPWeb web = site.OpenWeb();&lt;br /&gt;&lt;br /&gt;    site.AllowUnsafeUpdates = true;&lt;br /&gt;    web.AllowUnsafeUpdates = true;&lt;br /&gt;&lt;br /&gt;    SPFolder folder = web.Folders[docLib];&lt;br /&gt;&lt;br /&gt;    folder.Files.Add(saveAsFile, contents, true);&lt;br /&gt;&lt;br /&gt;    site.AllowUnsafeUpdates = false;&lt;br /&gt;    web.AllowUnsafeUpdates = false;&lt;br /&gt;&lt;br /&gt;    web.Close();&lt;br /&gt;    site.Close();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114123631600630055?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114123631600630055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114123631600630055' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114123631600630055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114123631600630055'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/03/wss-security-exception-when-upload.html' title='WSS : Security Exception when Upload File using WSS SDK'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-114068857449778407</id><published>2006-02-23T17:54:00.000+08:00</published><updated>2007-02-27T20:59:39.037+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sharepoint'/><title type='text'>WSS Multiple Templates DocLib</title><content type='html'>I have created a WSS Document Library list definition that allow user to create a new document from one of the many templates in a drop down menu.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://workspaces.gotdotnet.com/jywss" target="_blank"&gt;http://workspaces.gotdotnet.com/jywss&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-114068857449778407?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/114068857449778407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=114068857449778407' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114068857449778407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/114068857449778407'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/02/wss-multiple-templates-doclib.html' title='WSS Multiple Templates DocLib'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113953904643791140</id><published>2006-02-10T10:35:00.000+08:00</published><updated>2006-02-10T10:37:26.446+08:00</updated><title type='text'>WF not WWF</title><content type='html'>&lt;a href="http://blogs.msdn.com/jevdemon/archive/2006/02/09/529048.aspx" target="_blank"&gt;http://blogs.msdn.com/jevdemon/archive/2006/02/09/529048.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113953904643791140?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113953904643791140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113953904643791140' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113953904643791140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113953904643791140'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/02/wf-not-wwf.html' title='WF not WWF'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113929521131138756</id><published>2006-02-07T14:47:00.000+08:00</published><updated>2007-02-27T21:00:20.234+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><title type='text'>.NET20 : DPAPI Wrapper</title><content type='html'>In .NET 1.1, if you want to use DPAPI to protect your secret data, you need to use P/Invoke and write your own wrapper class to call the DPAPI function.&lt;br /&gt;&lt;br /&gt;However, In .NET 2.0, the DPAPI wrapper class has been built into the framework itself.The class is &lt;i&gt;ProtectedData&lt;/i&gt; in &lt;i&gt;System.Security.Cryptography&lt;/i&gt; namespace.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113929521131138756?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113929521131138756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113929521131138756' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113929521131138756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113929521131138756'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/02/net20-dpapi-wrapper.html' title='.NET20 : DPAPI Wrapper'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113837637344636039</id><published>2006-01-27T23:35:00.000+08:00</published><updated>2007-02-27T21:00:23.914+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project'/><title type='text'>PS2003: Sort view by name</title><content type='html'>All the views in Project Server Web Access are currently not sorted by the view name. Instead they are sort by the ViewID. This could pose a usability problem when you have a long list of views. Your users will need to scroll through the whole list to find the view they want.&lt;br /&gt;&lt;br /&gt;If you are really desperate in getting the view to sort by name, there are 2 stored proc in the Project Server database that control the retrieving of views.&lt;br /&gt;&lt;br /&gt;The 2 SP are &lt;i&gt;MSP_WEB_SP_SEC_GetAllResViewsByType&lt;/i&gt; and &lt;i&gt;MSP_WEB_SP_SEC_GetAllResProjectViewsByProject&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;To order view by name, add the following order clause at the end of the SELECT statement:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;order by wview_name&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;However, modifying the SP is not supported. Do it at your own risk.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113837637344636039?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113837637344636039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113837637344636039' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113837637344636039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113837637344636039'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/01/ps2003-sort-view-by-name.html' title='PS2003: Sort view by name'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113791608568025555</id><published>2006-01-22T15:45:00.000+08:00</published><updated>2007-02-27T21:00:28.468+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sharepoint'/><title type='text'>WSS Web Part Library Project Template for VS2005</title><content type='html'>I have created a WSS Web Part Library Project Template for Visual Studio 2005. It is&lt;br /&gt;now published on GotDotNet. The URL is:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://workspaces.gotdotnet.com/jywss" target="_blank"&gt;http://workspaces.gotdotnet.com/jywss&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113791608568025555?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113791608568025555/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113791608568025555' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113791608568025555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113791608568025555'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2006/01/wss-web-part-library-project-template.html' title='WSS Web Part Library Project Template for VS2005'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113548748102298400</id><published>2005-12-25T13:07:00.000+08:00</published><updated>2007-02-27T21:00:50.383+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>C# 2.0 : Property Access Modifier</title><content type='html'>In C# 2.0, you can specified different access for your property getter and setter.&lt;br /&gt;&lt;br /&gt;In the folloing example, your can specify the getter for your Name property to have public access, but your setter is protected, which is only accessible from derived class.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;public string Name&lt;br /&gt;{&lt;br /&gt;    get&lt;br /&gt;    {&lt;br /&gt;        return name;&lt;br /&gt;    }&lt;br /&gt;    protected set&lt;br /&gt;    {&lt;br /&gt;        name = value;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113548748102298400?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113548748102298400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113548748102298400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113548748102298400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113548748102298400'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/12/c-20-property-access-modifier.html' title='C# 2.0 : Property Access Modifier'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113530964953090147</id><published>2005-12-23T11:45:00.000+08:00</published><updated>2007-02-27T21:01:30.972+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>C# 2.0 : ?? Operator</title><content type='html'>C# 2.0 introduce a new operator "??". Make no mistake, it is a double question mark.&lt;br /&gt;&lt;br /&gt;This operator evaluate an expression and return the value of the expression if not null, else return a default value.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;a ?? "default"&lt;/i&gt; is equivalent to :&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;  if(a == null)&lt;br /&gt;    return "default";&lt;br /&gt;  else&lt;br /&gt;    return a;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Try the following example:&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;static void Main(string[] args)&lt;br /&gt;{&lt;br /&gt;    string aa = "abcd";&lt;br /&gt;  &lt;br /&gt;   // This will print "abcd".&lt;br /&gt;   Console.WriteLine("aa is {0}", aa ?? "default text");&lt;br /&gt;  &lt;br /&gt;   aa = null;&lt;br /&gt;   // This will print "default text".&lt;br /&gt;   Console.WriteLine("aa is {0}", aa ?? "default text");  &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Coming up next : Visual Studio 2005 Debugger Visualizer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113530964953090147?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113530964953090147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113530964953090147' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113530964953090147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113530964953090147'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/12/c-20-operator.html' title='C# 2.0 : ?? Operator'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113387842458814641</id><published>2005-12-06T22:06:00.000+08:00</published><updated>2005-12-06T22:13:44.600+08:00</updated><title type='text'>My 2005 reading list</title><content type='html'>Hitting my target again of reading 5 books a year. My reading list this year is:&lt;br /&gt;&lt;br /&gt;How Would You Move Mount Fuji&lt;br /&gt;.NET Application Architecture&lt;br /&gt;The Art of Deception&lt;br /&gt;Professional Software Development&lt;br /&gt;The Art of Long View.&lt;br /&gt;Show Stopper.&lt;br /&gt;The Design of Everyday Thing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Currently reading : The Search.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113387842458814641?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113387842458814641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113387842458814641' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113387842458814641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113387842458814641'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/12/my-2005-reading-list.html' title='My 2005 reading list'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113387632537164223</id><published>2005-12-06T21:36:00.000+08:00</published><updated>2007-02-27T21:00:55.314+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sharepoint'/><title type='text'>WSS : Display document library in another WSS site (Caveat)</title><content type='html'>You can insert a Page Viewer Web Part into a WSS site that show the document library of another site by specifying the following URL for the Page Viewer Web Part:&lt;br /&gt;&lt;br /&gt;http://[Server]/[Site Path]/_vti_bin/owssvr.dll?dialogview=FileOpen&amp;location=DocLibName&lt;br /&gt;&lt;br /&gt;Follow the link below to read about it.&lt;br /&gt;&lt;a href="http://digitalmelon.com/posts/214.aspx" target="_blank"&gt;How to display a single document library in another WSS site?&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;However, this does not work if your WSS site is created using the "Project Workspace" site definition. "Project Workspace"is a site definition which is added by Project Server 2003 when you install Project Server 2003.&lt;br /&gt;&lt;br /&gt;You will notice the Page Viewer Web Part will flash the document library for a while and then it will turn to a blank page. If you View Source on the Web Part, the content is actually still there.&lt;br /&gt;&lt;br /&gt;After some digging around, I found out it is cause by the JavaScript inserted by the "Project Workspace" definition.&lt;br /&gt;&lt;br /&gt;If you look into Template\LAYOUTS\1033\PWAINC\CUSTOM.JS, it register the GlobalInit() function to be called on page load. Going into the function you will see the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;function GlobalInit()&lt;br /&gt;{&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    if(window.parent != window)&lt;br /&gt;    {&lt;br /&gt;      bHostedinPWA = true;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  catch(e)&lt;br /&gt;  {&lt;br /&gt;    bHostedinPWA = true;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Basically what it does is it check whether the page is loaded in the top level browser window. If not(EG: You load it inside a IFRAME), it will hide the contents(you can learn about this if you trace deeper into the code).&lt;br /&gt;&lt;br /&gt;One workaround is to remove that checking in custom.js.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113387632537164223?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113387632537164223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113387632537164223' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113387632537164223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113387632537164223'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/12/wss-display-document-library-in.html' title='WSS : Display document library in another WSS site (Caveat)'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113310600084327734</id><published>2005-11-27T23:45:00.000+08:00</published><updated>2007-02-27T21:01:52.912+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DotNet'/><title type='text'>Using DebuggerStepThroughAttribute</title><content type='html'>You can use &lt;a href="http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemDiagnosticsDebuggerStepThroughAttributeClassTopic.asp" target="_blank"&gt;&lt;i&gt;System.Diagnostics.DebuggerStepThroughAttribute&lt;/i&gt;&lt;/a&gt; to prevent the Visual Studio debugger from stopping at the method/property call when you step through you code.&lt;br /&gt;&lt;br /&gt;For example, you have a program like this :&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solidcolor:#000000;" &gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;1&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;2&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Diagnostics;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;3&lt;/span&gt;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;4&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; DebuggerStepThrough_Demo&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;5&lt;/span&gt;{&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;6&lt;/span&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Employee&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;7&lt;/span&gt;    {&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;8&lt;/span&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Employee()&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;9&lt;/span&gt;        {&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;10&lt;/span&gt;            _name = &lt;span style="color:#848284;"&gt;""&lt;/span&gt;;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;11&lt;/span&gt;            _salary = 0;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;12&lt;/span&gt;        }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;13&lt;/span&gt;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;14&lt;/span&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Employee(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; name, &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; salary)&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;15&lt;/span&gt;        {&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;16&lt;/span&gt;            _name = name;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;17&lt;/span&gt;            _salary = salary;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;18&lt;/span&gt;        }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;19&lt;/span&gt;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;20&lt;/span&gt;        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; _salary;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;21&lt;/span&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; Salary&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;22&lt;/span&gt;        {&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;23&lt;/span&gt;            set { _salary = value; }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;24&lt;/span&gt;            get { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _salary; }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;25&lt;/span&gt;        }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;26&lt;/span&gt;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;27&lt;/span&gt;        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; _name;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;28&lt;/span&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; Name&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;29&lt;/span&gt;        {&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;30&lt;/span&gt;            set { _name = value; }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;31&lt;/span&gt;            get { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _name; }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;32&lt;/span&gt;        }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;33&lt;/span&gt;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;34&lt;/span&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; IncreaseSalary(&lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; amount)&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;35&lt;/span&gt;        {&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;36&lt;/span&gt;            Salary += amount;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;37&lt;/span&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; Salary;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;38&lt;/span&gt;        }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;39&lt;/span&gt;    }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;40&lt;/span&gt;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;41&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Class1&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;42&lt;/span&gt; {&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;43&lt;/span&gt;  [STAThread]&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;44&lt;/span&gt;  &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Main(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;45&lt;/span&gt;  {&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;46&lt;/span&gt;            Employee emp = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Employee(&lt;span style="color:#848284;"&gt;"My Name"&lt;/span&gt;, 1000);&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;47&lt;/span&gt;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;48&lt;/span&gt;            emp.IncreaseSalary(emp.Salary * 0.5);&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;49&lt;/span&gt;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;50&lt;/span&gt;  }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;51&lt;/span&gt; }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;52&lt;/span&gt;}&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;53&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When you put a breakpoint at the line &lt;i&gt;emp.IncreaseSalary(emp.Salary * 0.5);&lt;/i&gt;, and you step through the code in the debugger, the debugger will step into the get method of Salary property before the &lt;i&gt;IncreaseSalary&lt;/i&gt; method. You can stop this by using the DebuggerStepThroughAttribute attribute.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solidcolor:#000000;" &gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;1&lt;/span&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; Salary&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;2&lt;/span&gt;        {&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;3&lt;/span&gt;            set { _salary = value; }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;4&lt;/span&gt;&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;5&lt;/span&gt;            [DebuggerStepThrough()]           &lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;6&lt;/span&gt;            get { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _salary; }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;7&lt;/span&gt;        }&lt;br /&gt;&lt;span style="BORDER-RIGHT: #999999 1px solid; WIDTH: 40px; COLOR: #008284; MARGIN-RIGHT: 10px; BACKGROUND-: rightcolor:#e5e5e5;" &gt;8&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now, when you step through the code again in debugger, the debugger will step into IncreaseSalary right away.&lt;br /&gt;&lt;br /&gt;This is useful if your property getter and setter does not perform complex situation and you don't want&lt;br /&gt;to step into those code during debugging.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113310600084327734?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113310600084327734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113310600084327734' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113310600084327734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113310600084327734'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/11/using-debuggerstepthroughattribute.html' title='Using DebuggerStepThroughAttribute'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113310242990704209</id><published>2005-11-27T22:38:00.000+08:00</published><updated>2007-02-27T21:02:00.963+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visualstudio'/><title type='text'>Method Navigation Key in VStudio</title><content type='html'>In Visual Studio, You can place your cursor on a method or property call and hit &lt;i&gt;F12&lt;/i&gt; to go to the method/property definition.&lt;br /&gt;&lt;br /&gt;Similarly, when you are in the method/property definition, you can place your cursor on the method/property name, hit &lt;i&gt;Shift+F12&lt;/i&gt; to goto the method/property reference. Then you can use &lt;i&gt;Ctrl+Shift+1&lt;/i&gt; to move to the next reference or &lt;i&gt;Ctrl+Shift+2&lt;/i&gt; to move to the previous reference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113310242990704209?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113310242990704209/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113310242990704209' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113310242990704209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113310242990704209'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/11/method-navigation-key-in-vstudio.html' title='Method Navigation Key in VStudio'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113181674967586986</id><published>2005-11-13T01:32:00.000+08:00</published><updated>2005-11-13T01:32:29.676+08:00</updated><title type='text'>The Power of Blog</title><content type='html'>Blogging is such a wonderful innovation that allow individuals to share ideas and knowledge across the Internet.&lt;br /&gt;&lt;br /&gt;I just found out &lt;a href="http://blog.spsclerics.com/archive/2005/11/09/23271.aspx" target="_blank"&gt;someone&lt;/a&gt; has benefited from my ealier blog on the subject &lt;a href="http://dataerror.blogspot.com/2005/08/javascript-function-overriding-part-4.html" target="_blank"&gt;Javascript function override&lt;/a&gt; and has use that idea in his work.&lt;br /&gt;&lt;br /&gt;Knowing this fact is a great motivation for me to continue blogging.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113181674967586986?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113181674967586986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113181674967586986' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113181674967586986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113181674967586986'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/11/power-of-blog.html' title='The Power of Blog'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-113031221004975706</id><published>2005-10-26T15:35:00.000+08:00</published><updated>2005-10-26T15:36:50.403+08:00</updated><title type='text'>VMware Player</title><content type='html'>VMware Player is free software that enables PC users to easily run any virtual machine on a Windows or Linux PC. VMware Player runs virtual machines created by VMware Workstation, GSX Server or ESX Server and also supports Microsoft virtual PC and Symantec LiveState Recovery disk formats. &lt;br /&gt;&lt;br /&gt;For more details see : &lt;a herf="http://www.vmware.com/products/player/" target="_blank"&gt;http://www.vmware.com/products/player/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-113031221004975706?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/113031221004975706/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=113031221004975706' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113031221004975706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/113031221004975706'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/10/vmware-player.html' title='VMware Player'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112972348392181594</id><published>2005-10-22T12:13:00.000+08:00</published><updated>2005-10-22T12:14:18.050+08:00</updated><title type='text'>MakeCab : Part 3 - Compress multiple files in multiple folders</title><content type='html'>By default, MakeCab does not preserve folder path when it compress the files.&lt;br /&gt;&lt;br /&gt;Try the following directive file and check the CAB file. You will notice the path information is not in the CAB file. Replace the file list with your actual files.&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin:0px 0px 0px 0px; border:solid 1px 1px 1px 1px;"&gt;&lt;br /&gt;.OPTION EXPLICIT       &lt;br /&gt;&amp;nbsp;&lt;br /&gt;.Set CabinetNameTemplate=mycab.CAB &lt;br /&gt;&amp;nbsp;&lt;br /&gt;.Set Cabinet=on&lt;br /&gt;.Set Compress=on&lt;br /&gt;&amp;nbsp;&lt;br /&gt;"file1.pdf"&lt;br /&gt;"folder1\file2.doc"&lt;br /&gt;"folder2\This is a third file.doc"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To preserve the path information, you have to use the &lt;i&gt;DestinationDir&lt;/i&gt; directive. Modify the directive file to look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin:0px 0px 0px 0px; border:solid 1px 1px 1px 1px;"&gt;&lt;br /&gt;.OPTION EXPLICIT       &lt;br /&gt;&amp;nbsp;&lt;br /&gt;.Set CabinetNameTemplate=mycab.CAB &lt;br /&gt;&amp;nbsp;&lt;br /&gt;.Set Cabinet=on&lt;br /&gt;.Set Compress=on&lt;br /&gt;&amp;nbsp;&lt;br /&gt;"file1.pdf"&lt;br /&gt;&amp;nbsp;&lt;br /&gt;.Set DestinationDir=folder1&lt;br /&gt;"folder1\file2.doc"&lt;br /&gt;&amp;nbsp;&lt;br /&gt;.Set DestinationDir=folder2&lt;br /&gt;"folder2\This is a third file.doc"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Run the MakeCab against the directive file and open the CAB file. You should see the path information is preserved.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112972348392181594?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112972348392181594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112972348392181594' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112972348392181594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112972348392181594'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/10/makecab-part-3-compress-multiple-files.html' title='MakeCab : Part 3 - Compress multiple files in multiple folders'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112972323037871810</id><published>2005-10-20T19:57:00.000+08:00</published><updated>2005-10-20T20:04:16.610+08:00</updated><title type='text'>MakeCab : Part 2 - Compress multiple files</title><content type='html'>To compress multiple files into a single CAB file, you need to use a directive file.&lt;br /&gt;The directive file contain instruction how MakeCab should compress and package the files.&lt;br /&gt;&lt;br /&gt;Below is a sample of the most basic directive file. Replace the file list with your actual files.&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin:0px 0px 0px 0px; border:solid 1px 1px 1px 1px;"&gt;&lt;br /&gt;.OPTION EXPLICIT&lt;br /&gt;&amp;nbsp;&lt;br /&gt;.Set CabinetNameTemplate=mycab.CAB &lt;br /&gt;&amp;nbsp;&lt;br /&gt;.Set Cabinet=on&lt;br /&gt;.Set Compress=on&lt;br /&gt;&amp;nbsp;&lt;br /&gt;"file1.pdf"&lt;br /&gt;"file2.doc"&lt;br /&gt;"This is a third file.doc"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All directive start with ".". Comment start with ";".&lt;br /&gt;&lt;br /&gt;In the above example, &lt;br /&gt;&lt;i&gt;option explicit&lt;/i&gt; specify all variables must be declared before it is used.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;CabinetNameTemplate&lt;/i&gt; specify the name of the output CAB file.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Cabinet&lt;/i&gt; specify whether include the files in the CAB file. When creating setup package, you can use this directive to exclude certain file such as setup.exe from being included into the CAB file.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Compress&lt;/i&gt; specify whether to compress the file.&lt;br /&gt;&lt;br /&gt;The remaining lines specify the files to be included into the CAB file.&lt;br /&gt;&lt;br /&gt;To compress the files using the directive file, run the following command:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;makecab /f your_directive_file.ddf&lt;/pre&gt;.&lt;br /&gt;&lt;br /&gt;Once completed, the CAB file will be created inside a folder named "disk1". Two more files, setup.inf and setup.rpt is also created. You can just take the CAB file and ignore the others.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112972323037871810?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112972323037871810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112972323037871810' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112972323037871810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112972323037871810'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/10/makecab-part-2-compress-multiple-files.html' title='MakeCab : Part 2 - Compress multiple files'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112972298896094382</id><published>2005-10-19T19:54:00.000+08:00</published><updated>2005-10-19T20:01:18.146+08:00</updated><title type='text'>MakeCab : Part 1 - Compress single file</title><content type='html'>Makecab is a utility mainly used for packaging setup program and compression.&lt;br /&gt;&lt;br /&gt;For the discussion of this blog, I will only focus on compression. Makecab is a handy tool to compress files. Makecab come with Windows XP and Windows Server 2003(not sure about Windows 2000) and both OS recoginze the CAB file and able to extract it without any compression utility installed.&lt;br /&gt;&lt;br /&gt;I found this very useful when I work on production server where there is no compression utility like Winzip is installed. For example, there was once I need to copy a database file which is about 250MB to another PC and to my thumb drive. It is a huge file to copy. So I use MakeCab to compress the file before copying it out.&lt;br /&gt;&lt;br /&gt;However, Makecab is a command line utility and using it is not that straight forward.&lt;br /&gt;&lt;br /&gt;I will walkthrough 3 scenario of using Makecab to compress file.&lt;br /&gt;1) Compress single file.&lt;br /&gt;2) Compress multiple files in the same folder.&lt;br /&gt;3) Compress multiple files in multiple folders.&lt;br /&gt;&lt;br /&gt;It is very straight forward to compress a single file. Go to your command line and run the following command:&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin:0px 0px 0px 0px; border:solid 1px 1px 1px 1px;"&gt;makecab your_source_file cab_file_name.cab&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For example, to compress a readme.doc to readme.cab, the command is :&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin:0px 0px 0px 0px; border:solid 1px 1px 1px 1px;"&gt;makecab readme.doc readme.cab&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112972298896094382?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112972298896094382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112972298896094382' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112972298896094382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112972298896094382'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/10/makecab-part-1-compress-single-file.html' title='MakeCab : Part 1 - Compress single file'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112947422667089878</id><published>2005-10-16T22:48:00.000+08:00</published><updated>2007-02-27T21:58:23.575+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Bad Error Message Hinder Productivity</title><content type='html'>I was writing an C# Console application which I use System.Web.Mail.SmtpMail to send&lt;br /&gt;email out. System.Web.Mail.SmtpMail internally use CDO for Windows 200 (CDOSys) to&lt;br /&gt;send the mail out.&lt;br /&gt;&lt;br /&gt;While my application was running, I got an exception when calling the SmtpMail.Send()&lt;br /&gt;method. The exception message was :&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Could not access CDO.Message object.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;At first thought, the exception could be due to one of the following reasons:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The CDOSys.dll component is not registered properly on the machine.&lt;br /&gt;&lt;li&gt;The application does not have enough permission to read the registry and instantiate the component.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;So, I went on to search the MSDN for the possible cause and mitigation of error. I found a few KB articles and try the settings suggested in the articles and still not luck. I try a couple more things to try to get it work. After half an hour, still nothing was working.&lt;br /&gt;&lt;br /&gt;So I decide to reference the CDOSys.dll using COM interop in my C# project and replace the original code with calls to CDO.Message directly. When I ran the application, the exception message I got was :&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Unable to connect to SMTP server&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Now, things become helpful.I check my SMTP server setting and found out that I gave the wrong IP. I type in the correct SMTP Server IP, ran the app again and everything work now. I move on to put back my original System.Web.Mail.SmtpMail code with the correct SMTP Server IP and get everything working. This whole process took me only 5 minutes.&lt;br /&gt;&lt;br /&gt;If the System.Web.Mail.SmtpMail.Send() throw an exception with more precise message, it would have save me 30 minutes time for looking at the wrong thing.&lt;br /&gt;&lt;br /&gt;The lesson here is :&lt;br /&gt;If you does not return a meaningful exception/error message which precisely describe the error, you will drive your user nuts and mislead them into looking at the wrong remedy. This will essentially make your API/application less usable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112947422667089878?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112947422667089878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112947422667089878' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112947422667089878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112947422667089878'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/10/bad-error-message-hinder-productivity.html' title='Bad Error Message Hinder Productivity'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112701013112429969</id><published>2005-09-18T10:21:00.000+08:00</published><updated>2007-02-27T21:03:11.679+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>TSQL date teaser. Bonus Question</title><content type='html'>Given a date, how do you tell which week in the month is that date?&lt;br /&gt;EG : Given 1-Feb-2005, it is the 1st week in February.&lt;br /&gt;Given 17-Feb-2005, it is the 3rd week in February.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;declare @startOfMonth datetime&lt;br /&gt;declare @myDate datetime&lt;br /&gt;declare @weekOfYearForStartOfMonth int&lt;br /&gt;declare @weekInMonth int&lt;br /&gt;&lt;br /&gt;select @myDate = '17-feb-2005'&lt;br /&gt;select @startOfMonth = dateadd(d, (day(@myDate)-1)* -1, @myDate)&lt;br /&gt;select @weekOfYearForStartOfMonth = datepart(ww, @startOfMonth)&lt;br /&gt;select datepart(ww, @myDate) - @weekOfYearForStartOfMonth + 1&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112701013112429969?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112701013112429969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112701013112429969' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112701013112429969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112701013112429969'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/09/tsql-date-teaser-bonus-question.html' title='TSQL date teaser. Bonus Question'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112678864082658888</id><published>2005-09-15T20:45:00.000+08:00</published><updated>2007-02-27T21:01:35.075+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>C# Language Innovation. Must Watch!</title><content type='html'>Anders Hejlsberg has a great video on Channel 9 which show case the great innovation they have done on C# 3.0 and .NET Framework 3.0.&lt;br /&gt;&lt;br /&gt;The Language Integrated Query (LINQ) and type inferencing capability is really impressive.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://channel9.msdn.com/Showpost.aspx?postid=114680" target="_blank"&gt;Anders Hejlsberg - LINQ&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112678864082658888?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112678864082658888/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112678864082658888' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112678864082658888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112678864082658888'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/09/c-language-innovation-must-watch.html' title='C# Language Innovation. Must Watch!'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112653645531310518</id><published>2005-09-15T20:35:00.001+08:00</published><updated>2007-02-27T21:03:29.255+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>TSQL date teaser. Answer for Q6</title><content type='html'>6) A slight variation from (5), given a date, find the second Thursday&lt;br /&gt;of the month.&lt;br /&gt;E.G: Given 10-July-2005, second Thursday of the month is 14-July-2005.&lt;br /&gt;&lt;br /&gt;Your solution must also be able to find (N)th (day of the week) of the month.&lt;br /&gt;Where : N can be first week, second week and so on.&lt;br /&gt;day of week can be any day from Sunday to Saturday.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;declare @startOfNextMonth datetime&lt;br /&gt;declare @endOfMonth datetime&lt;br /&gt;declare @myDate varchar(20)&lt;br /&gt;declare @DaysToAdd int&lt;br /&gt;declare @NthWeek int&lt;br /&gt;declare @TargetDayOfWeek int&lt;br /&gt;&lt;br /&gt;select @myDate = '10-July-2005'&lt;br /&gt;&lt;br /&gt;select @TargetDayOfWeek = 5&lt;br /&gt;select @NthWeek = 2&lt;br /&gt;&lt;br /&gt;select @startOfMonth = dateadd(d, (day(@myDate)-1)* -1, @myDate)&lt;br /&gt;&lt;br /&gt;select @DaysToAdd = (7 - ((datepart(dw,@startOfMonth) +&lt;br /&gt;                        (7 - @TargetDayOfWeek)) % 7)) % 7&lt;br /&gt;&lt;br /&gt;select dateadd(d, @DaysToAdd + ((@nthWeek-1)*7), @startOfMonth)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112653645531310518?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112653645531310518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112653645531310518' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112653645531310518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112653645531310518'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/09/tsql-date-teaser-answer-for-q6.html' title='TSQL date teaser. Answer for Q6'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112653589075590483</id><published>2005-09-15T20:35:00.000+08:00</published><updated>2007-02-27T21:03:32.717+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>TSQL date teaser. Answer for Q5</title><content type='html'>5). Given a date, find the first Tuesday of the month.&lt;br /&gt;E.G: Given 10-July-2005, first Tuesday for the month is 5-July-2005.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;declare @startOfNextMonth datetime&lt;br /&gt;declare @endOfMonth datetime&lt;br /&gt;declare @myDate varchar(20)&lt;br /&gt;declare @DaysToAdd int&lt;br /&gt;declare @TargetDayOfWeek int&lt;br /&gt;&lt;br /&gt;select @myDate = '10-jul-2005'&lt;br /&gt;select @TargetDayOfWeek = 3&lt;br /&gt;&lt;br /&gt;select @startOfMonth = dateadd(d, (day(@myDate)-1)* -1, @myDate)&lt;br /&gt;print  @startOfMonth&lt;br /&gt;&lt;br /&gt;select @DaysToAdd = (7 - ((datepart(dw,@startOfMonth) +&lt;br /&gt;                          (7 - @TargetDayOfWeek)) % 7)) % 7&lt;br /&gt;&lt;br /&gt;select dateadd(d, @DaysToAdd, @startOfMonth)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112653589075590483?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112653589075590483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112653589075590483' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112653589075590483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112653589075590483'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/09/tsql-date-teaser-answer-for-q5.html' title='TSQL date teaser. Answer for Q5'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112653544367916859</id><published>2005-09-14T23:58:00.000+08:00</published><updated>2007-02-27T21:03:35.672+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>TSQL date teaser. Answer for Q4</title><content type='html'>4) A slight variation from (3), given a date, find the second last Thursday&lt;br /&gt;of the month.&lt;br /&gt;E.G: Given 10-July-2005, second last Thursday of the month is 21-July-2005.&lt;br /&gt;&lt;br /&gt;Your solution must also be able to find (N)th last (day of the week) of the month.&lt;br /&gt;Where : N can be last week, second last week, third last week and so on,&lt;br /&gt;day of week can be any day from Sunday to Saturday.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;declare @startOfNextMonth datetime&lt;br /&gt;declare @endOfMonth datetime&lt;br /&gt;declare @myDate varchar(20)&lt;br /&gt;declare @DaysToMinus int&lt;br /&gt;declare @NthWeek int&lt;br /&gt;declare @TargetDayOfWeek int&lt;br /&gt;&lt;br /&gt;select @myDate = '10-jul-2005'&lt;br /&gt;select @NthWeek = 2&lt;br /&gt;select @TargetDayOfWeek = 5&lt;br /&gt;&lt;br /&gt;select @startOfMonth = dateadd(d, (day(@myDate)-1)* -1, @myDate)&lt;br /&gt;select @startOfNextMonth = dateadd(m, 1, @startOfMonth)&lt;br /&gt;select @endOfMonth = dateadd(d, -1 , @startOfNextMonth)&lt;br /&gt;&lt;br /&gt;select @DaysToMinus = ((datepart(dw,@endOfMonth) + (7-@TargetDayOfWeek)) % 7)&lt;br /&gt;select dateadd(d, -(@DaysToMinus + ((@nthWeek-1)*7)), @endOfMonth)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112653544367916859?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112653544367916859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112653544367916859' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112653544367916859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112653544367916859'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/09/tsql-date-teaser-answer-for-q4.html' title='TSQL date teaser. Answer for Q4'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112641772206172671</id><published>2005-09-13T23:10:00.000+08:00</published><updated>2007-02-27T21:03:38.426+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>TSQL date teaser. Answer for Q3</title><content type='html'>3). Given a date, find the last Friday of the month.&lt;br /&gt;E.G: Given 10-July-2005, last Friday for the month is 29-July-2005.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;declare @startOfNextMonth datetime&lt;br /&gt;declare @endOfMonth datetime&lt;br /&gt;declare @myDate varchar(20)&lt;br /&gt;declare @DaysToMinus int&lt;br /&gt;&lt;br /&gt;select @myDate = '10-jul-2005'&lt;br /&gt;&lt;br /&gt;select @startOfMonth = dateadd(d, (day(@myDate)-1)* -1, @myDate)&lt;br /&gt;print  @startOfMonth&lt;br /&gt;&lt;br /&gt;select @startOfNextMonth = dateadd(m, 1, @startOfMonth)&lt;br /&gt;print  @startOfNextMonth&lt;br /&gt;&lt;br /&gt;select @endOfMonth = dateadd(d, -1 , @startOfNextMonth)&lt;br /&gt;print  @endOfMonth&lt;br /&gt;&lt;br /&gt;select @DaysToMinus = -((datepart(dw,@endOfMonth) + 1) % 7)&lt;br /&gt;&lt;br /&gt;select dateadd(d, @DaysToMinus, @endOfMonth)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112641772206172671?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112641772206172671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112641772206172671' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112641772206172671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112641772206172671'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/09/tsql-date-teaser-answer-for-q3.html' title='TSQL date teaser. Answer for Q3'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112641734484698364</id><published>2005-09-12T22:48:00.000+08:00</published><updated>2007-02-27T21:03:45.545+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>TSQL date teaser. Answer for Q2</title><content type='html'>2) Given a date, find the date of the first day and last day of the month.&lt;br /&gt;E.G: Given 21-July-2005, You have to tell 1-July-2005 is the first day of&lt;br /&gt;the month and 31-July-2005 is the last day of the month.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;declare @startOfNextMonth datetime&lt;br /&gt;declare @endOfMonth datetime&lt;br /&gt;declare @myDate varchar(20)&lt;br /&gt;&lt;br /&gt;select @myDate = '21-feb-2005'&lt;br /&gt;&lt;br /&gt;select @startOfMonth = dateadd(d, (day(@myDate)-1)* -1, @myDate)&lt;br /&gt;print  @startOfMonth&lt;br /&gt;&lt;br /&gt;select @startOfNextMonth = dateadd(m, 1, @startOfMonth)&lt;br /&gt;print  @startOfNextMonth&lt;br /&gt;&lt;br /&gt;select @endOfMonth = dateadd(d, -1 , @startOfNextMonth)&lt;br /&gt;print  @endOfMonth &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112641734484698364?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112641734484698364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112641734484698364' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112641734484698364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112641734484698364'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/09/tsql-date-teaser-answer-for-q2.html' title='TSQL date teaser. Answer for Q2'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112641662807483509</id><published>2005-09-11T13:29:00.000+08:00</published><updated>2007-02-27T21:03:49.238+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>TSQL date teaser. Answer for Q1</title><content type='html'>This is a long outstanding post to my previous &lt;a href="http://dataerror.blogspot.com/2005/07/tsql-date-teaser.html" target="_blank"&gt;TSQL date teaser post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;1) Given a date, find the date of the first day and last day of that week.&lt;br /&gt;E.G: Given 28-July-2005, You have to tell 24-July-2005 is the first day&lt;br /&gt;of that week and 30-July-2005 is that last day of that week.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;declare @dayOfWeek int&lt;br /&gt;declare @startOfWeek datetime&lt;br /&gt;declare @endOfWeek datetime&lt;br /&gt;declare @myDate varchar(20)&lt;br /&gt;&lt;br /&gt;select @myDate = '28-july-2005'&lt;br /&gt;select @dayOfWeek = datepart(dw, @myDate)&lt;br /&gt;&lt;br /&gt;select @startOfWeek = dateadd(d, (@dayOfWeek - 1)* -1, @myDate)&lt;br /&gt;print  @startOfWeek&lt;br /&gt;&lt;br /&gt;select @endOfWeek = dateadd(d, 7 - @dayOfWeek , @myDate)&lt;br /&gt;print  @endOfWeek&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112641662807483509?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112641662807483509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112641662807483509' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112641662807483509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112641662807483509'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/09/tsql-date-teaser-answer-for-q1.html' title='TSQL date teaser. Answer for Q1'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112573016499427384</id><published>2005-09-03T14:50:00.000+08:00</published><updated>2005-09-03T14:49:25.000+08:00</updated><title type='text'>Free XML Editor</title><content type='html'>I always keep some freeware tools in my thumbdrive and take it with me wherever I go. It is especially useful when I do work at customer place. I obviously can't install unlicense software in their machine, so the option will be to use free tools.&lt;br /&gt;&lt;br /&gt;Here are 2 FREE! XML editor which I find very nice.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.xmlfox.com" target="_blank"&gt;XMLFox freeware XML Editor&lt;/a&gt;&lt;br /&gt;XML and XSD editing&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.wmhelp.com" target="_blank"&gt;XMLPad&lt;/a&gt;&lt;br /&gt;XML Editing.&lt;br /&gt;XSLT Transform.&lt;br /&gt;XPath Evaluation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112573016499427384?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112573016499427384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112573016499427384' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112573016499427384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112573016499427384'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/09/free-xml-editor.html' title='Free XML Editor'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112536382787748455</id><published>2005-08-30T09:00:00.000+08:00</published><updated>2007-02-27T21:22:46.116+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Javascript function overriding, Part 4</title><content type='html'>In this final part of the Javascript function override series, I will give you a coding scenario when the 2 method of function overriding will make a difference to your code and a scenario in which I have use method 2 to extend feature functionality.&lt;br /&gt;&lt;br /&gt;If you want to refer back to my previous post, follow these links :&lt;br /&gt;&lt;a href="http://dataerror.blogspot.com/2005/08/javascript-function-overriding-part-1.html" target="_blank"&gt;Part 1&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dataerror.blogspot.com/2005/08/javascript-function-overriding-part-2.html" target="_blank"&gt;Part 2&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dataerror.blogspot.com/2005/08/javascript-function-overriding-part-3.html" target="_blank"&gt;Part 3&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The answer to the first question is very obvious. From the 2 example I have given, if your new override function need to call the orginal function, then you have to use method 2. Otherwise you will end up with a recursive function call if you use method 1.&lt;br /&gt;&lt;br /&gt;Here come the second part which is more interesting. Recently I use the second method to extend the functionality and overcome some limitation in Windows Sharepoint Services (WSS).&lt;br /&gt;&lt;br /&gt;I am not going to go in great length what is WSS. You can find out more on this product from the &lt;a href="http://www.microsoft.com/sharepoint" target="_blank"&gt;Microsoft Sharepoint website&lt;/a&gt;. In a glance, WSS provide a website for team and departmental collaboration. In each WSS site, you can create picture library, document library, link list to other website, survey poll and custom list to store some custom information and many more.&lt;br /&gt;&lt;br /&gt;For the sake of this discussion, I will only focus on custom list. But the method I describe here is equally&lt;br /&gt;applicable to other lists as well.&lt;br /&gt;&lt;br /&gt;In the list view, when you hover over each list item, a context menu will be popup. The context menu consist of menu items which offer you actions that you can perform on the item. Behind the scene, there is a series of Javascript function calls which make all these happen. At one point in the call chain, the client side script framework will call a function named &lt;i&gt;AddListMenuItems(m, ctx)&lt;/i&gt; (you can find this function is ows.js). This function is responsible to construct the menu item that is relevant to the list item.&lt;br /&gt;&lt;br /&gt;If you look into this function, one of the first thing it does is call another function named &lt;i&gt;Custom_AddListMenuItems(m, ctx)&lt;/i&gt;. According to the Microsoft documentation, if you want to add your own menu item to the context menu, you should create the function &lt;i&gt;Custom_AddListMenuItems(m, ctx)&lt;/i&gt; and add your own code to create the extra menu items in this function. This provide some form of extensibility point.&lt;br /&gt;&lt;br /&gt;So far so good, except for 2 thing :&lt;br /&gt;1) Your custom menu items always appear before the default menu items provided by WSS.&lt;br /&gt;2) You always have to work on the &lt;i&gt;Custom_AddListMenuItems(m, ctx)&lt;/i&gt; function to add your own menu items. Imagine a situation where multiple developers each is dealing with a different set of requirements and they each need to add their own custom menu item. Then it become difficult and messy to maintain the function because it is work by multiple developers and the single function might contain many complex logic to construct the menu item.&lt;br /&gt;&lt;br /&gt;Using the javascript capability I demonstrated in method 2 of my example, I come out with a way to insert menu item at the back of the default menu items and allow the creation of each menu item to be encapsulate into different functions.&lt;br /&gt;&lt;br /&gt;The idea and steps is pretty simple:&lt;br /&gt;1) I create an array which is use to store the custom function.&lt;br /&gt;2) When the page is loaded, I add the original &lt;i&gt;AddListMenuItems()&lt;/i&gt; to the array.&lt;br /&gt;3) Each time a new menu item need to be added, the menu item creation code can be put into a different function, and this function is added into the array.&lt;br /&gt;4) I override the &lt;i&gt;AddListMenuItems&lt;/i&gt; function to do something different. My version of the function will loop through the array and call each function in the array to contruct the menu item they are responsible for.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here are the javascript code that does the logic:&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&amp;lt;script language="javascript"&amp;gt;&lt;br /&gt;&lt;br /&gt;var AddListMenuItemsFuncList;&lt;br /&gt;AddListMenuItemsFuncList = new Array();&lt;br /&gt;&lt;br /&gt;AddListMenuItemsFuncList[AddListMenuItemsFuncList.length] = AddListMenuItems;&lt;br /&gt;&lt;br /&gt;AddListMenuItems = function(m, ctx)&lt;br /&gt;{&lt;br /&gt;    for(ctr=0; ctr &amp;lt; AddListMenuItemsFuncList.length; ctr++)&lt;br /&gt;    {&lt;br /&gt;        AddListMenuItemsFuncList[ctr](m, ctx);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;function MyMenuItemFunction1(m, ctx)&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    var strDisplayText = "Custom Action 1";&lt;br /&gt;    var strAction;&lt;br /&gt;    var strImagePath = "";&lt;br /&gt;&lt;br /&gt;    strAction = "alert('Custom Action 1 " + itemTable.ItemId + "')";&lt;br /&gt;   &lt;br /&gt;    // Add menu item&lt;br /&gt;    CAMOpt(m, strDisplayText, strAction, strImagePath);&lt;br /&gt;   &lt;br /&gt;    // add a separator to the menu&lt;br /&gt;    CAMSep(m);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function MyMenuItemFunction2(m, ctx)&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    var strDisplayText = "Custom Action 2";&lt;br /&gt;    var strAction;&lt;br /&gt;    var strImagePath = "";&lt;br /&gt;&lt;br /&gt;    strAction = "alert('Custom Action 2 " + itemTable.ItemId + "')";&lt;br /&gt;   &lt;br /&gt;    // Add menu item&lt;br /&gt;    CAMOpt(m, strDisplayText, strAction, strImagePath);&lt;br /&gt;   &lt;br /&gt;    // add a separator to the menu&lt;br /&gt;    CAMSep(m);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;function insertFunctionAt(arr, idx, newFunc)&lt;br /&gt;{&lt;br /&gt;    for(ctr=arr.length-1; ctr &amp;gt;=idx; ctr--)&lt;br /&gt;    {&lt;br /&gt;        arr[ctr+1] = arr[ctr];&lt;br /&gt;    }&lt;br /&gt;   &lt;br /&gt;    arr[idx] = newFunc;&lt;br /&gt;    return arr;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function addFunctionToMenu(funcPointer)&lt;br /&gt;{&lt;br /&gt; AddListMenuItemsFuncList[AddListMenuItemsFuncList.length] = funcPointer;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Add this custom menu item to the back of the default menu items.&lt;br /&gt;addFunctionToMenu(MyMenuItemFunction1);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// Add this custom menu item before the default menu items.&lt;br /&gt;insertFunctionAt(AddListMenuItemsFuncList, 0, MyMenuItemFunction2);&lt;br /&gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To see this code in action, add a Content Editor Web Part(CEWP) to your custom list's view page. You can show the Web Part Tool Pane by adding &lt;i&gt;?ToolPaneView=2&lt;/i&gt; to the end of the URL(This is an unsupported method). Then open the Source Editor, paste the above code into the Source Editor and click OK to save. Now refresh the view page. If you hover over the list item, you will see the new custom menu item in the context menu.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;One Last Word&lt;/h3&gt;&lt;br /&gt;Although the function override capability in Javascript is powerful, it work like a double sided sword. If you don't use it with careful thought, you can be killed for the same reason.&lt;br /&gt;&lt;br /&gt;Using it to extend the custom menu items in WSS provide you with greater flexibility, but we are also making an assumption on the behavior of the &lt;i&gt;AddListMenuItems&lt;/i&gt; function. Microsoft does not guarantee that this function will not change in future release or Service Pack. If it does, then your code might just break.&lt;br /&gt;&lt;br /&gt;To put it in simple words, I think this technique work fine, except that it is an unsupported method, and use it with care.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112536382787748455?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112536382787748455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112536382787748455' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112536382787748455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112536382787748455'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/08/javascript-function-overriding-part-4.html' title='Javascript function overriding, Part 4'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112519880488066362</id><published>2005-08-28T11:12:00.000+08:00</published><updated>2005-08-28T11:14:27.033+08:00</updated><title type='text'>Podcast Link</title><content type='html'>&lt;u&gt;.NET&lt;/u&gt;&lt;br /&gt;&lt;a href="http://www.franklins.net/dotnetrocks" target="_blank"&gt;.NET Rocks&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;SQL Server&lt;/u&gt;&lt;br /&gt;&lt;a href="http://www.sqldownunder.com/" target="_blank"&gt;SQL Down Under Portal&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;ASP.NET&lt;/u&gt;&lt;br /&gt;&lt;a href="http://weblogs.asp.net/wallym" target="_blank"&gt;Wallace B. McClure&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Office&lt;/u&gt;&lt;br /&gt;&lt;a href="http://geeklenet.typepad.com/ozpodcast/" target="_blank"&gt;Office Zealot&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Agile Development&lt;/u&gt;&lt;br /&gt;&lt;a href="http://www.teamagile.com/mainpages/Interviews.html" target="_blank"&gt;Team Agile&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112519880488066362?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112519880488066362/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112519880488066362' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112519880488066362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112519880488066362'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/08/podcast-link.html' title='Podcast Link'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112519819298629923</id><published>2005-08-28T10:59:00.000+08:00</published><updated>2007-02-27T21:22:53.169+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Javascript function overriding, Part 3</title><content type='html'>In this installment, I will give you the code of how to prove what I have said.&lt;br /&gt;&lt;br /&gt;To prove my point for method 1, create the following HTML page :&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script language="javascript"&amp;gt;&lt;br /&gt;var base_foo;&lt;br /&gt;&lt;br /&gt;function foo()&lt;br /&gt;{&lt;br /&gt;    alert('foo is called');&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;base_foo = foo;&lt;br /&gt;&lt;br /&gt;function foo()&lt;br /&gt;{&lt;br /&gt;    base_foo();&lt;br /&gt;    alert('override foo is called');&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function clickme()&lt;br /&gt;{&lt;br /&gt;    foo();&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;input type="button" value="click me" onclick="clickme()"/&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you click on the button, clickme() will be called which in turn call foo(), you will end up with a stack overflow exception.&lt;br /&gt;&lt;br /&gt;This is because &lt;i&gt;base_foo&lt;/i&gt; and &lt;i&gt;foo&lt;/i&gt; point to the same memory address, when foo() call base_foo(), it is essentially a recursive function call.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To prove my point for method 2, create the following HTML page :&lt;pre style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; MARGIN: 0px; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script language="javascript"&amp;gt;&lt;br /&gt;var base_foo;&lt;br /&gt;&lt;br /&gt;function foo(yourname)&lt;br /&gt;{&lt;br /&gt;    alert('Hello ' + yourname);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;base_foo = foo;&lt;br /&gt;&lt;br /&gt;foo = function(yourname)&lt;br /&gt;{&lt;br /&gt;    base_foo(yourname);&lt;br /&gt;    alert('(overide) Hello ' + yourname);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;function clickme()&lt;br /&gt;{&lt;br /&gt;    foo('Jonathan');&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;input type="button" value="click me" onclick="clickme()"/&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you click on the button, clickme() will be called which in turn will call foo(), what you will see now is 'Hello Jonathan' will be display, and then follow by '(override) Hello Jonathan'.&lt;br /&gt;&lt;br /&gt;This show that &lt;i&gt;base_foo&lt;/i&gt; and &lt;i&gt;foo&lt;/i&gt; point to different memory address.&lt;br /&gt;&lt;br /&gt;In the next final part of this series, I will give you a scenario when the 2 method will make a difference and a case study where I have use method 2 to override function.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112519819298629923?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112519819298629923/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112519819298629923' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112519819298629923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112519819298629923'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/08/javascript-function-overriding-part-3.html' title='Javascript function overriding, Part 3'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112506461016405548</id><published>2005-08-26T21:53:00.000+08:00</published><updated>2007-02-27T21:22:56.261+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Javascript function overriding, Part 2</title><content type='html'>Continue from the &lt;a href="http://dataerror.blogspot.com/2005/08/javascript-function-overriding-part-1.html" target="_blank"&gt;part 1&lt;/a&gt;, I will give a more detail explaination to what I say in Part 1.&lt;br /&gt;&lt;br /&gt;Using the same example : &lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="BACKGROUND-COLOR: #00dddd"&gt;&lt;pre style="MARGIN: 0px"&gt;Method 1&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="BACKGROUND-COLOR: #ffdd00"&gt;&lt;pre&gt;&amp;lt;script language="javascript"&amp;gt;&lt;br /&gt;var base_foo;&lt;br /&gt;&lt;br /&gt;function foo()&lt;br /&gt;{&lt;br /&gt;    alert('foo is called');&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;base_foo = foo;&lt;br /&gt;&lt;br /&gt;function foo()&lt;br /&gt;{&lt;br /&gt;    alert('override foo is called');&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The first time you create function foo(), your code will be loaded into a arbitary memory location, say for example 0x001a.&lt;br /&gt;&lt;br /&gt;Your function pointer &lt;i&gt;foo&lt;/i&gt; will be set to point to address 0x001a.&lt;br /&gt;&lt;br /&gt;Next you assign &lt;i&gt;base_foo&lt;/i&gt; to point to the same memory address pointed to by &lt;i&gt;foo&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Now, your override function foo() to do different thing. The script engine will load your new code into the same memory location (0x001a).&lt;br /&gt;&lt;br /&gt;And both your function pointer &lt;i&gt;foo&lt;/i&gt; and &lt;i&gt;base_foo&lt;/i&gt; will remain point to the same address.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Moving to method 2:&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="BACKGROUND-COLOR: #00dddd"&gt;&lt;pre style="MARGIN: 0px"&gt;Method 2&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="BACKGROUND-COLOR: #ffdd00"&gt;&lt;pre&gt;&amp;lt;script language="javascript"&amp;gt;&lt;br /&gt;var base_foo;&lt;br /&gt;&lt;br /&gt;function foo(yourname)&lt;br /&gt;{&lt;br /&gt;    alert('Hello ' + yourname);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;base_foo = foo;&lt;br /&gt;&lt;br /&gt;foo = function(yourname)&lt;br /&gt;{&lt;br /&gt;    alert('(overide) Hello ' + yourname);&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The first time you create function foo(), your code will be loaded into a arbitary memory location, say for example 0x001a.&lt;br /&gt;&lt;br /&gt;Your function pointer &lt;i&gt;foo&lt;/i&gt; will be set to point to address 0x001a.&lt;br /&gt;&lt;br /&gt;Next you assign &lt;i&gt;base_foo&lt;/i&gt; to point to the same memory address pointed to by &lt;i&gt;foo&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Now you override function foo() to do different thing:&lt;pre style="MARGIN: 0px"&gt;&lt;br /&gt;foo = function(yourname)&lt;br /&gt;{&lt;br /&gt;    // your new code&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What happen now is your new code is loaded into a new memory location, say (0x002a).&lt;br /&gt;&lt;br /&gt;Your function pointer &lt;i&gt;foo&lt;/i&gt; will now be changed to point to address 0x002a. But &lt;i&gt;base_foo&lt;/i&gt; remain point to 0x001a.&lt;br /&gt;&lt;br /&gt;In the next part, I will give an example of how to prove this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112506461016405548?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112506461016405548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112506461016405548' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112506461016405548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112506461016405548'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/08/javascript-function-overriding-part-2.html' title='Javascript function overriding, Part 2'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112488730649324935</id><published>2005-08-24T20:39:00.000+08:00</published><updated>2007-02-27T21:22:59.169+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Javascript function overriding, Part 1</title><content type='html'>&lt;i&gt;Disclaimer : All the javascript code, explaination and description in this blog series is particular to Internet Explorer only.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;In Javascript, you can overide a function using the following method : &lt;table style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="BACKGROUND-COLOR: #00dddd"&gt;&lt;pre style="MARGIN: 0px"&gt;Method 1&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="BACKGROUND-COLOR: #ffdd00"&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;lt;script language="javascript"&amp;gt;&lt;br /&gt;function foo()&lt;br /&gt;{&lt;br /&gt;    alert('foo is called');&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function foo()&lt;br /&gt;{&lt;br /&gt;    alert('override foo is called');&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;If you call foo(), it will display 'override foo is called'.&lt;br /&gt;&lt;br /&gt;Recently, I discover another way of overriding function : &lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="BACKGROUND-COLOR: #00dddd"&gt;&lt;pre style="MARGIN: 0px"&gt;Method 2&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="BACKGROUND-COLOR: #ffdd00"&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;lt;script language="javascript"&amp;gt;&lt;br /&gt;function foo(yourname)&lt;br /&gt;{&lt;br /&gt;    alert('Hello ' + yourname);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;foo = function(yourname)&lt;br /&gt;{&lt;br /&gt;    alert('(overide) Hello ' + yourname);&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Both method will accomplish the same thing. However, they are semantically different.&lt;br /&gt;&lt;br /&gt;Using method 1, what happen is the new code will over-write the existing code at the same memory address.&lt;br /&gt;&lt;br /&gt;In method 2, the new code will be loaded into a different memory address and the function pointer &lt;i&gt;foo&lt;/i&gt; will be changed to point to this new memory address.&lt;br /&gt;&lt;br /&gt;What does this mean ? I will give an example and show you how to prove what I say in my &lt;a href="http://dataerror.blogspot.com/2005/08/javascript-function-overrriding-part-2.html" target="_blank"&gt;next post&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112488730649324935?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112488730649324935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112488730649324935' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112488730649324935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112488730649324935'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/08/javascript-function-overriding-part-1.html' title='Javascript function overriding, Part 1'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112307447279669378</id><published>2005-08-03T21:06:00.000+08:00</published><updated>2005-08-03T21:07:52.803+08:00</updated><title type='text'>Shortcut to Lock Your Workstation</title><content type='html'>Here is how you can quickly lock your workstation without doing the CTRL+ALT+DEL thing :&lt;br /&gt;&lt;br /&gt;create a shortcut to &lt;b&gt;rundll32.exe user32.dll,LockWorkStation&lt;/b&gt;. &lt;br /&gt;Then, launch the shortcut to lock the workstation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112307447279669378?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112307447279669378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112307447279669378' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112307447279669378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112307447279669378'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/08/shortcut-to-lock-your-workstation.html' title='Shortcut to Lock Your Workstation'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112260459936984089</id><published>2005-07-29T10:38:00.000+08:00</published><updated>2007-02-27T21:13:27.916+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>TSQL Date Teaser</title><content type='html'>Do you think you can solve the following problems using SQL Server TSQL ?&lt;br /&gt;&lt;br /&gt;1) Given a date, find the date of the first day and last day of that week.&lt;br /&gt;E.G: Given 28-July-2005, You have to tell 24-July-2005 is the first day&lt;br /&gt;of that week and 30-July-2005 is that last day of that week.&lt;br /&gt;&lt;br /&gt;2) Given a date, find the date of the first day and last day of the month.&lt;br /&gt;E.G: Given 21-July-2005, You have to tell 1-July-2005 is the first day of&lt;br /&gt;the month and 31-July-2005 is the last day of the month.&lt;br /&gt;&lt;br /&gt;3). Given a date, find the last Friday of the month.&lt;br /&gt;E.G: Given 10-July-2005, last Friday for the month is 29-July-2005.&lt;br /&gt;&lt;br /&gt;4) A slight variation from (3), given a date, find the second last Thursday&lt;br /&gt;of the month.&lt;br /&gt;E.G: Given 10-July-2005, second last Thursday of the month is 21-July-2005.&lt;br /&gt;&lt;br /&gt;Your solution must also be able to find (N)th last (day of the week) of the month.&lt;br /&gt;Where : N can be last week, second last week, third last week and so on,&lt;br /&gt;day of week can be any day from Sunday to Saturday.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5). Given a date, find the first Tuesday of the month.&lt;br /&gt;E.G: Given 10-July-2005, first Tuesday for the month is 5-July-2005.&lt;br /&gt;&lt;br /&gt;6) A slight variation from (5), given a date, find the second Thursday&lt;br /&gt;of the month.&lt;br /&gt;E.G: Given 10-July-2005, second Thursday of the month is 14-July-2005.&lt;br /&gt;&lt;br /&gt;Your solution must also be able to find (N)th (day of the week) of the month.&lt;br /&gt;Where : N can be first week, second week and so on.&lt;br /&gt;day of week can be any day from Sunday to Saturday.&lt;br /&gt;&lt;br /&gt;Condition :&lt;br /&gt;1) You can only use TSQL Date and Time function.&lt;br /&gt;2) Only simple expressions are allowed. (EG : add, minus, multiply, divide, assignment, variables).&lt;br /&gt;3) Language element such as Loop, if..else, case statement are not allowed.&lt;br /&gt;4) Assume first day of the week is Sunday and last day of the week is Saturday(which is default in most&lt;br /&gt;SQL Server installation).&lt;br /&gt;5) You can't deal with leap year explicitly. Meaning, you cannot write your own algorithm to check&lt;br /&gt;for leap years. You are only allowed to use TSQL DateTime function.&lt;br /&gt;&lt;br /&gt;Try it and I will post the solutions by the next 2 weeks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112260459936984089?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112260459936984089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112260459936984089' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112260459936984089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112260459936984089'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/07/tsql-date-teaser.html' title='TSQL Date Teaser'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112184561890655121</id><published>2005-07-20T15:50:00.000+08:00</published><updated>2007-02-27T21:23:10.917+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sharepoint'/><title type='text'>Improving performance of the web part page gallery</title><content type='html'>If you find it can sometimes take 20 to 30 seconds to return the web part gallery so that you can drop a web part onto a web part page then this post is for you.&lt;br /&gt;&lt;br /&gt;The problem may be because SharePoint is trying to contact the online web part gallery, however, if your machine is not connected to the internet, or the proxy is not configured properly, then it could take some time to actually work this out. This is the delay you are seeing.&lt;br /&gt;&lt;br /&gt;You can easily turn off the web part gallery by following these simple steps:&lt;br /&gt;&lt;br /&gt;1. Open SharePoint Central Administration (make sure you are on the Windows SharePoint Services page)&lt;br /&gt;&lt;br /&gt;2. Click on "Configure Virtual Server"&lt;br /&gt;&lt;br /&gt;3. Select the Virtual Server on which you are experiencing the delay&lt;br /&gt;&lt;br /&gt;4. Click "Manage Security Settings for Web Part Pages"&lt;br /&gt;&lt;br /&gt;5. Select the "Disabled" option next to "Online Web Part Gallery" and click OK.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112184561890655121?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112184561890655121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112184561890655121' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112184561890655121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112184561890655121'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/07/improving-performance-of-web-part-page.html' title='Improving performance of the web part page gallery'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112166906603878684</id><published>2005-07-18T14:38:00.000+08:00</published><updated>2005-07-18T14:44:26.046+08:00</updated><title type='text'>2 pair of shoes &amp;&amp; 1pair of sandals.</title><content type='html'>What a year it is! This year alone I have wear off 2 pair of shoes and 1 pair of sandals.&lt;br /&gt;&lt;br /&gt;I broke my first pair of shoe when I was in Hong Kong couple of months ago.&lt;br /&gt;The second pair wore off yesterday while I was tracking in a forest reserve.&lt;br /&gt;And my sandals is just a "natural die-off".&lt;br /&gt;&lt;br /&gt;Perhaps it is time for a change.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112166906603878684?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112166906603878684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112166906603878684' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112166906603878684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112166906603878684'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/07/2-pair-of-shoes-1pair-of-sandals.html' title='2 pair of shoes &amp;&amp; 1pair of sandals.'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112097624498934892</id><published>2005-07-10T14:13:00.000+08:00</published><updated>2007-02-27T21:23:05.089+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Floating box using CSS layout</title><content type='html'>&lt;div style="BORDER-RIGHT: #000 1px solid; BORDER-TOP: #000 1px solid; BORDER-LEFT: #000 1px solid; WIDTH: 600px; BORDER-BOTTOM: #000 1px solid"&gt;&lt;br /&gt;How do you create a floating box which is attached to a particular corner of a layout container like this :&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style="BORDER-RIGHT: #000 1px solid; BORDER-TOP: #000 1px solid; BACKGROUND: #ffffff; BORDER-LEFT: #000 1px solid; WIDTH: 500px; BORDER-BOTTOM: #000 1px solid"&gt;&lt;br /&gt;&lt;div style="BORDER-RIGHT: #ff0000 1px solid; BORDER-TOP: #ff0000 1px solid; BACKGROUND: #dddddd; FLOAT: left; BORDER-LEFT: #ff0000 1px solid; WIDTH: 230px; BORDER-BOTTOM: #ff0000 1px solid; HEIGHT: 50px"&gt;&lt;br /&gt;This is in a box.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I'm sitting in a hotel room in San Francisco working on a project that can't wait until I get back to my office, and all I can think about is my reliance on connectivity. I, and a bunch of other happy developers, am here because of the VSLive/VBits conference. Trouble is, I didn't bring everything I need for my work, so now I desperately need a network connection. Sure, I have dial-up access in the hotel room, but though quick enough for e-mail, it's anything but practical for large file transfers.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Sound like a familiar situation? Well, it happens to me all the time, and usually it's a pain. This time, however, I decided I'm not going to be beaten by mere, piddling circumstances. I am, after all, a developer. Not only that, I'm a developer looking for a good time (developing that is). I'm going to solve this problem—and turn the solution into this month's article.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Okay. So let's say there is a file that I need and I can't wait until I'm back in Redmond. For instance, let's say it is the demo for Impossible Creatures (which is a whopping 285 MB), and that I really, really need it for some serious research. As I said, my dial-up access is slower than a dead snail, but there is wireless in a nearby coffee shop that should be considerably faster.&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The key is to use the CSS &lt;b&gt;&lt;a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/float.asp" target="_blank"&gt;float&lt;/a&gt;&lt;/b&gt; attribute.&lt;br /&gt;&lt;br /&gt;For example to create the above layout, use the following css style and sample:&lt;br /&gt;&lt;br /&gt;&lt;pre style="WIDTH: 500px"&gt;&lt;br /&gt;&amp;lt;style type="text/css"&amp;gt;&lt;br /&gt;&lt;br /&gt;#main&lt;br /&gt;{&lt;br /&gt;    border:1px solid #000;&lt;br /&gt;    background:#ffffff;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#main #floatbox {&lt;br /&gt;    background: #dddddd;&lt;br /&gt;    float: left;&lt;br /&gt;    width: 230px;&lt;br /&gt;    height : 50px;&lt;br /&gt;    border: #ff0000 1px solid;&lt;br /&gt;}&lt;br /&gt;&amp;lt;/style&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div id="main"&amp;gt;&lt;br /&gt;&amp;lt;div id="floatbox"&amp;gt;&lt;br /&gt;This is in a box.&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;I'm sitting in a hotel room in San Francisco working on a project that can't wait until I get back to my office, and all I can think about is my reliance on connectivity. I, and a bunch of other happy developers, am here because of the VSLive/VBits conference. Trouble is, I didn't bring everything I need for my work, so now I desperately need a network connection. Sure, I have dial-up access in the hotel room, but though quick enough for e-mail, it's anything but practical for large file transfers.&lt;br /&gt;&amp;lt;p&amp;gt;&lt;br /&gt;Sound like a familiar situation? Well, it happens to me all the time, and usually it's a pain. This time, however, I decided I'm not going to be beaten by mere, piddling circumstances. I am, after all, a developer. Not only that, I'm a developer looking for a good time (developing that is). I'm going to solve this problem—and turn the solution into this month's article.&lt;br /&gt;&amp;lt;p&amp;gt;&lt;br /&gt;Okay. So let's say there is a file that I need and I can't wait until I'm back in Redmond. For instance, let's say it is the demo for Impossible Creatures (which is a whopping 285 MB), and that I really, really need it for some serious research. As I said, my dial-up access is slower than a dead snail, but there is wireless in a nearby coffee shop that should be considerably faster.&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112097624498934892?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112097624498934892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112097624498934892' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112097624498934892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112097624498934892'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/07/floating-box-using-css-layout.html' title='Floating box using CSS layout'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-112046049610646392</id><published>2005-07-04T14:59:00.000+08:00</published><updated>2005-07-04T15:01:36.113+08:00</updated><title type='text'>Notepad Replacement</title><content type='html'>I have been using other text editors as notepad replacement for quite some time. I &lt;br /&gt;highly recommend the following 2 editors (all free):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flos-freeware.ch/" target="_blank"&gt;Notepad2&lt;/a&gt;&lt;br&gt;&lt;br /&gt;&lt;a href="http://notepad-plus.sourceforge.net/uk/site.htm" target="_blank"&gt;Notepad++&lt;/a&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;Both support features like :&lt;br /&gt;-Line number display.&lt;br /&gt;-Syntax Highlighting.&lt;br /&gt;-Bookmark.&lt;br /&gt;-Zooming.&lt;br /&gt;-Show White Space and Line End character.&lt;br /&gt;-Small in size. Put into your PenDrive and you are good to go.&lt;br /&gt;-Does not require installation. Unzip the file and you are ready to rock and roll.&lt;br /&gt;-and many more.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There subtle difference between the two is :&lt;br /&gt;Notepad2 :&lt;br /&gt;-SDI interface.&lt;br /&gt;-Consume less memory.&lt;br /&gt;&lt;br /&gt;Notepad++ :&lt;br /&gt;-MDI interface.&lt;br /&gt;-Consume more memory than Notepad2.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-112046049610646392?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/112046049610646392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=112046049610646392' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112046049610646392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/112046049610646392'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/07/notepad-replacement.html' title='Notepad Replacement'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7690408.post-111772069417844168</id><published>2005-06-02T21:55:00.000+08:00</published><updated>2005-06-02T22:06:06.756+08:00</updated><title type='text'>New XML File Formats for Office 12</title><content type='html'>Word, Excel and PowerPoint will get new default file formats based on XML.  The extensions will change from .DOC, .XLS, .PPT to .DOCX, .XLSX, .PPTX.&lt;br /&gt;&lt;br /&gt;The new file format is actually enclosed in a ZIP file. Change the extension name to .ZIP and you'll be able to double-click and get access to all the pieces of the new format.  There will be updates for previous versions of Office to enable this file format to be used with those apps too.&lt;br /&gt;&lt;br /&gt;For more info there is a video interview with Brian Jones on Channel9, Brian is blogging now, and there are a couple of White Papers on MSDN giving some technical details.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=73329" target="_blank"&gt;http://channel9.msdn.com/ShowPost.aspx?PostID=73329&lt;/a&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://download.microsoft.com/download/c/2/9/c2935f83-1a10-4e4a-a137-c1db829637f5/Office12FileFormatDevPreviewWP.doc" target="_blank"&gt;http://download.microsoft.com/download/c/2/9/c2935f83-1a10-4e4a-a137-c1db829637f5/Office12FileFormatDevPreviewWP.doc&lt;/a&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://download.microsoft.com/download/c/2/9/c2935f83-1a10-4e4a-a137-c1db829637f5/Office12NewFileFormatsWP.doc" target="_blank"&gt;http://download.microsoft.com/download/c/2/9/c2935f83-1a10-4e4a-a137-c1db829637f5/Office12NewFileFormatsWP.doc&lt;/a&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7690408-111772069417844168?l=dataerror.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dataerror.blogspot.com/feeds/111772069417844168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7690408&amp;postID=111772069417844168' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/111772069417844168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7690408/posts/default/111772069417844168'/><link rel='alternate' type='text/html' href='http://dataerror.blogspot.com/2005/06/new-xml-file-formats-for-office-12.html' title='New XML File Formats for Office 12'/><author><name>Jonathan Yong</name><uri>http://www.blogger.com/profile/06417429484136277876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
