<?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-1736021189436054208</id><updated>2012-02-01T16:30:35.811+01:00</updated><category term='Fisheye'/><category term='firesheep'/><category term='relations'/><category term='wifi'/><category term='robocopy'/><category term='visual-studio'/><category term='free'/><category term='programming'/><category term='development'/><category term='latex'/><category term='memoization'/><category term='property-sheets'/><category term='sync'/><category term='project-management'/><category term='vsprop'/><category term='iphone'/><category term='results'/><category term='xcopy'/><category term='c++0x'/><category term='GPS'/><category term='windows'/><category term='exception'/><category term='routing'/><category term='vpn'/><category term='SVN'/><category term='c++'/><category term='management'/><category term='backup'/><title type='text'>Xavier Nodet's blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-1662511307009904341</id><published>2012-01-06T21:52:00.002+01:00</published><updated>2012-01-06T22:34:06.022+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='latex'/><category scheme='http://www.blogger.com/atom/ns#' term='free'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><category scheme='http://www.blogger.com/atom/ns#' term='project-management'/><title type='text'>LaTeX-like Project Management</title><content type='html'>With project management role comes the need for a project scheduling tool. &amp;nbsp;The obvious choice would be &lt;a href="http://www.microsoft.com/project/en-us/project-management.aspx"&gt;Microsoft Project&lt;/a&gt;, but I thought I'd rather look for some free programs first.&lt;br /&gt;&lt;br /&gt;I tried two that are very similar to MS-Project: &lt;a href="http://sourceforge.net/projects/openproj/"&gt;OpenProj&lt;/a&gt; and &lt;a href="http://www.ganttproject.biz/"&gt;GanttProject&lt;/a&gt;. &amp;nbsp;Both are open-source software. &amp;nbsp;Both have a GUI that's centered around a Gantt chart, and allow you to manipulate activities as in MS-Project. &amp;nbsp;But both also lack a very basic feature: resource leveling. &amp;nbsp;They don't have any intelligence whatsoever, and the user must check by himself that resources are not overloaded, and correct issues by adding spurious precedence&amp;nbsp;or 'starts after'&amp;nbsp;constraints. &amp;nbsp;I therefore don't really see how to actually use these tools for any serious work...&lt;br /&gt;&lt;br /&gt;But then I discovered &lt;a href="http://www.taskjuggler.org/"&gt;The TaskJuggler&lt;/a&gt;. &amp;nbsp;It's a command-line program written in Ruby that will read a text file and output HTML pages with various reports like a gantt chart or a resource allocation graph. &amp;nbsp;Installing the tool is as easy (once/if you have Ruby) as typing '&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;gem install taskjuggler&lt;/span&gt;'.&lt;br /&gt;&lt;br /&gt;Using a text file as the input for all your project data has important benefits. The first one is that you can make use of your Source Management system to allow multiple people to collaborate on the file, while with a binary file (or even a text file that's completely rewritten by your tool when you save it) can't effectively permit sharing. &amp;nbsp;Another is that changes are much easier to track, as a change to a single part of the project will not touch the rest of the file. &amp;nbsp;So it's possible to revert individual changes...&lt;br /&gt;&lt;br /&gt;This very much reminds me the difference between a word processing program, and LaTeX...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here are some screenshots:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="margin-left: auto; margin-right: auto;"&gt;&lt;a href="http://www.blogger.com/goog_1279380411"&gt;&lt;img border="0" height="195" src="http://3.bp.blogspot.com/-Gu7Njbg5aJg/TwdhtVn7UpI/AAAAAAAAAMA/swBTe0pubYA/s400/ttj-tuto.png" width="400" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://www.taskjuggler.org/tj3/examples/Tutorial/Overview.html"&gt;The Gantt chart&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="margin-left: auto; margin-right: auto;"&gt;&lt;a href="http://www.blogger.com/goog_1279380415"&gt;&lt;img border="0" height="337" src="http://3.bp.blogspot.com/-GYPOJsoVgwU/TwdiDDvnaBI/AAAAAAAAAMI/YPTt08Od1sc/s400/ttj-tuto-res.png" width="400" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://www.taskjuggler.org/tj3/examples/Tutorial/ResourceGraph.html"&gt;The resource allocation chart&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;And here is an example of a trivial project file.&amp;nbsp;You'll find a much more complete example of a project file in&amp;nbsp;&lt;a href="http://www.taskjuggler.org/tj3/manual/Tutorial.html"&gt;the tutorial&lt;/a&gt;&amp;nbsp;that is provided with the project.&lt;br /&gt;&lt;br /&gt;&lt;pre class="gutter: false"&gt;project tiny "Example TJ3 Project"  2012-01-09 +12m {&lt;br /&gt;  timezone "Europe/Paris"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;resource Xavier "Xavier Nodet" {}&lt;br /&gt;&lt;br /&gt;resource dev "Developers" {&lt;br /&gt;  managers Xavier&lt;br /&gt;  resource dev1 "Dev1" {}&lt;br /&gt;  resource dev2 "Dev2" {}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;task Tiny "Our Tiny Project" {&lt;br /&gt;  responsible Xavier&lt;br /&gt;&lt;br /&gt;  task t1 "Task 1" {&lt;br /&gt;    &lt;br /&gt;    task sub1 "Sub-task 1.1" {&lt;br /&gt;      effort 30d&lt;br /&gt;      allocate dev1&lt;br /&gt;    }&lt;br /&gt;    task sub2 "Sub-task 1.2" {&lt;br /&gt;      effort 10d&lt;br /&gt;      allocate dev1&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  task t2 "Task 2" {&lt;br /&gt;    effort 20d&lt;br /&gt;    allocate dev2&lt;br /&gt;    depends !t1.sub1&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  task deliveries "Milestones" {&lt;br /&gt;&lt;br /&gt;    task start "Project start" {&lt;br /&gt;      start ${projectstart}&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    task ega "EGA" {&lt;br /&gt;      start 2012-11-01&lt;br /&gt;      depends !!t1, !!t2&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# Skipping the report generation part...&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;I only scratched the surface so far, but this seems very promising to me...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-1662511307009904341?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/1662511307009904341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2012/01/latex-like-project-management.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/1662511307009904341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/1662511307009904341'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2012/01/latex-like-project-management.html' title='LaTeX-like Project Management'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-Gu7Njbg5aJg/TwdhtVn7UpI/AAAAAAAAAMA/swBTe0pubYA/s72-c/ttj-tuto.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-9023774264056623389</id><published>2011-12-03T17:28:00.001+01:00</published><updated>2011-12-04T10:05:10.584+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='management'/><category scheme='http://www.blogger.com/atom/ns#' term='results'/><title type='text'>Results are not enough</title><content type='html'>Of course, results are a very important part of a manager's evaluation. &amp;nbsp;But that's not the end of the story...&lt;br /&gt;&lt;br /&gt;Consider the manager of a great team of engineers.  One can expect that the team will deliver good results.  And this may be the case even if the manager is not so great...  Conversely, let's consider the manager of a bad team: it may be the case that whatever the manager will do, the team will not deliver.  In the long run, a great manager will manage to improve the results he gets from the team, but it may take quite some time. Evaluation of the managers only from the team's results is thus not enough, and may even be completely counter-productive...&lt;br /&gt;&lt;br /&gt;So what's a good manager to do?&lt;br /&gt;&lt;br /&gt;Of course, a manager must make plans.  But that's not enough: as &lt;a href="http://managementblog.org/2011/11/30/but-we-are-results-based/"&gt;Tom Foster puts it&lt;/a&gt;, managers should build &lt;i&gt;robust&lt;/i&gt; plans that take external factors not under their control into account. And they should be judged on the fact that they not only planned for success, but made it more likely to happen. Luck, or the lack of it, should not play a role.&amp;nbsp;Kids learning chess often setup traps, only to discover that their opponent did you fall into it. They plan for the best, instead of planning for the worst. Explicitly supposing that things can go wrong is a good way to not depend on random external factors, and improve the likelihood of getting good results.&lt;br /&gt;&lt;br /&gt;Getting results is not the mark of a good manager. &amp;nbsp;&lt;i&gt;Consistently&lt;/i&gt; getting results is.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-9023774264056623389?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/9023774264056623389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2011/12/results-are-not-enough.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/9023774264056623389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/9023774264056623389'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2011/12/results-are-not-enough.html' title='Results are not enough'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-3889324372071888949</id><published>2011-03-31T16:24:00.000+02:00</published><updated>2011-03-31T16:24:52.917+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='SVN'/><title type='text'>Partial working copies with Subversion</title><content type='html'>When working on large and/or multi-platform projects, it often happens that your Subversion working copy contains items that are useless: ports for other platforms, module that you don't need for your work, etc.&lt;br /&gt;&lt;br /&gt;Recent Subversion versions allow to specify the maximum depth to use when updating a given target. &amp;nbsp;You can e.g. specify that you only want the files in a given directory, but not its sub-directories. &amp;nbsp;Or you want a given directory to be empty, or removed from the working copy entirely.&lt;br /&gt;&lt;br /&gt;Let's consider you've checked out an entire working copy, with the following structure:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;root&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;dir1&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;file1.1&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;file1.2&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;subdir1.1&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;subdir1.2&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;subdir1.3&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;subdir1.4&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;dir2&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;file2.1&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;subdir2.1&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;file2.1.1&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;dir3&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;file3.1&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;dir3.1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you're not interested anymore in &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;subdir2.1&lt;/span&gt; and its content, you can issue the following commands:&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;gt; cd root/dir2&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;gt; svn update --set-depth exclude subdir2.1&lt;/span&gt;&lt;br /&gt;Now &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;dir2&lt;/span&gt; only has &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;file2.1&lt;/span&gt;, and an '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;svn update&lt;/span&gt;'&amp;nbsp;command&amp;nbsp;that does not specify a '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;--set-depth&lt;/span&gt;' option will not bring back &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;subdir2.1&lt;/span&gt; or any of its content.&lt;br /&gt;&lt;br /&gt;If you're only interested in the files inside &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;dir1&lt;/span&gt;, but not the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;subdir1.*&lt;/span&gt;, you could do:&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;gt; cd root&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;gt; svn update --set-depth files dir1&lt;/span&gt;&lt;br /&gt;&lt;div&gt;This tells SVN to only get the files in &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;dir1&lt;/span&gt;, but not its sub-directories&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Similarly, you can use '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;--set-depth empty&lt;/span&gt;' to get an empty directory (this can be useful to ask for one of its sub-directories), '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;--set-depth immediates&lt;/span&gt;'&amp;nbsp;to get the immediate sub-directories, and use '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;--set-depth infinity&lt;/span&gt;' to restore the default and get everything in a given directory.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On the reverse, if you have to checkout a working copy but you know you only need some parts of it, you can use the '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;--depth&lt;/span&gt;' option (not '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;--set-depth&lt;/span&gt;', go figure...) of the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;checkout&lt;/span&gt; command. &amp;nbsp;Then you create your paths in your working copy, step by step:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;gt; svn checkout --depth empty [repository URL] root&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;gt; svn update --set-depth empty root/dir1&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;gt; svn update --set-depth infinity root/dir1/subdir1.2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;gt; svn update --set-depth infinity root/dir3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hope this helps!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-3889324372071888949?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/3889324372071888949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2011/03/partial-working-copies-with-subversion.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/3889324372071888949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/3889324372071888949'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2011/03/partial-working-copies-with-subversion.html' title='Partial working copies with Subversion'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-8566772832506314439</id><published>2011-03-18T18:51:00.015+01:00</published><updated>2011-03-18T21:21:51.839+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++0x'/><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='memoization'/><title type='text'>New features in C++0x allow really impressive stuff...</title><content type='html'>&lt;a href="http://slack.codemaniacs.com/"&gt;Slack&lt;/a&gt; has a very interesting blog entry about &lt;a href="http://slackito.com/2011/03/17/automatic-memoization-in-cplusplus0x"&gt;Automatic memoization in C++0x&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Memoization is a pretty well-known optimization technique which consists in “remembering” (i.e.: caching) the results of previous calls to a function, so that repeated calls with the same parameters are resolved without repeating the original computation.&lt;/blockquote&gt;&lt;br /&gt;He starts with the short and simple Python function that returns a memoized function from any regular one, and then shows how C++0x features can be used to do the same!&lt;br /&gt;&lt;br /&gt;Very impressive...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-8566772832506314439?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/8566772832506314439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2011/03/new-features-in-c0x-allow-really.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/8566772832506314439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/8566772832506314439'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2011/03/new-features-in-c0x-allow-really.html' title='New features in C++0x allow really impressive stuff...'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-994421963312969385</id><published>2011-01-05T12:55:00.002+01:00</published><updated>2011-01-05T17:22:19.328+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual-studio'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='Fisheye'/><category scheme='http://www.blogger.com/atom/ns#' term='SVN'/><title type='text'>Opening the Fisheye page for your current file from your IDE</title><content type='html'>Our revision control system is SVN, with a Fisheye server providing easy browsing of the repository.  I use Fisheye very much and was tired of having to dig through the deep hierarchies of our project to display the information about a file.  I therefore wrote a very little script that I can launch from Visual Studio to open the Fisheye page for the current file, with the correct branch/trunk information.&lt;br /&gt;&lt;br /&gt;This script assumes that the directory structure on the disk mimicks the directory structure on the SVN repository, with a prefix (here: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;f:\work&lt;/span&gt;): &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;f:\work\theProject\branches\aBranch\foo.txt&lt;/span&gt; corresponds to file &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;foo.txt&lt;/span&gt; in the root directory of project &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;theProject&lt;/span&gt; on branch &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;aBranch&lt;/span&gt;.  This will open page &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;https://your-fisheye-server/browse/theProject/branches/aBranch/foo.txt&lt;/span&gt;. Of course, you will probably want to edit the location of the server...&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: bat; gutter: false"&gt;rem&lt;br /&gt;rem Launch a browser directed to the Fisheye page for&lt;br /&gt;rem a particular file.&lt;br /&gt;rem&lt;br /&gt;rem mailto:xavier.nodet@gmail.com&lt;br /&gt;rem&lt;br /&gt;&lt;br /&gt;@echo off&lt;br /&gt;&lt;br /&gt;rem Assumption: first argument is a absolute path to the file&lt;br /&gt;rem on the disk for which we would like to display the&lt;br /&gt;rem corresponding Fisheye page.&lt;br /&gt;set FILE=%1&lt;br /&gt;&lt;br /&gt;rem Remove the "f:\work" prefix from the file path&lt;br /&gt;set FILE=%FILE:f:\work=%&lt;br /&gt;rem @echo %FILE%&lt;br /&gt;&lt;br /&gt;rem Replace all the backslashes with forward slashes&lt;br /&gt;set FILE=%FILE:\=/%&lt;br /&gt;rem @echo %FILE%&lt;br /&gt;&lt;br /&gt;start "c:\Program Files\Mozilla Firefox 4\firefox.exe" https://your-fisheye-server/browse%FILE%&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You will have to launch this script from your IDE with as single argument the full path to the file you want to see in Fisheye.  Here is how to do this from Visual Studio.  Open the 'Tools' -&amp;gt; 'External tools...' menu, click the 'Add' button, and fill the information needed, using $(ItemPath) for the argument:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_95_5-qo913g/TSRXALCvinI/AAAAAAAAAKE/majG4YnAEXE/s1600/greenshot_2011-01-05_12-23-29.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_95_5-qo913g/TSRXALCvinI/AAAAAAAAAKE/majG4YnAEXE/s1600/greenshot_2011-01-05_12-23-29.png" /&gt;&lt;/a&gt;&lt;/div&gt;You now have a 'Current file on Fisheye' entry on your Tools menu, that you simply have to choose to launch Firefox... &lt;br /&gt;&lt;br /&gt;I hope you'll find this useful...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-994421963312969385?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/994421963312969385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2011/01/opening-fisheye-page-for-your-current.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/994421963312969385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/994421963312969385'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2011/01/opening-fisheye-page-for-your-current.html' title='Opening the Fisheye page for your current file from your IDE'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_95_5-qo913g/TSRXALCvinI/AAAAAAAAAKE/majG4YnAEXE/s72-c/greenshot_2011-01-05_12-23-29.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-5344435093602297224</id><published>2010-12-15T10:52:00.005+01:00</published><updated>2011-01-05T17:27:07.605+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='exception'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Factoring exception handling code in C++</title><content type='html'>When writing exception handlers (e.g. around calls to database or network related code), you often end up with the same set of catch clauses at each call site. Suppose you end up with the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: cpp; gutter: false"&gt;try {&lt;br /&gt;  //...&lt;br /&gt;} catch (std::runtime_error&amp;amp; e) {&lt;br /&gt;  std::cout &amp;lt;&amp;lt; "Runtime error: " &amp;lt;&amp;lt; e.what() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;} catch (...) {&lt;br /&gt;  std::cout &amp;lt;&amp;lt; "Unknown exception!" &amp;lt;&amp;lt; std::endl;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You have this piece of code repeated dozens of times, which is not really a Good Thing(tm)... A little C++ trick can help you avoid those repetitions: (1)&amp;nbsp;factor the common code into a single function or method that rethrows the active exception and catches it immediately, and (2)&amp;nbsp;catch all exceptions at the call sites and call this handler!&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: cpp; gutter: false"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;stdexcept&amp;gt;&lt;br /&gt;&lt;br /&gt;void exception_handler() {&lt;br /&gt;  try {&lt;br /&gt;    throw; //rethrow the current exception&lt;br /&gt;  } catch (std::runtime_error&amp;amp; e) {&lt;br /&gt;    std::cout &amp;lt;&amp;lt; "Runtime error: " &amp;lt;&amp;lt; e.what() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  } catch (...) {&lt;br /&gt;    std::cout &amp;lt;&amp;lt; "Unknown exception!" &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;  try {&lt;br /&gt;    throw std::runtime_error("unable to comply...");&lt;br /&gt;  } catch (...) { exception_handler(); }&lt;br /&gt;&lt;br /&gt;  try {&lt;br /&gt;    throw 1;&lt;br /&gt;  } catch (...) { exception_handler(); }&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You must be careful to not call &lt;code&gt;exception_handler()&lt;/code&gt; outside a &lt;code&gt;catch&lt;/code&gt; clause: the &lt;code&gt;trow&lt;/code&gt; statement calls &lt;code&gt;terminate()&lt;/code&gt; if there is no active exception to rethrow!&lt;br /&gt;&lt;br /&gt;You may wonder if one could use the &lt;code&gt;std::uncaught_exception()&lt;/code&gt; function to protect against this.  &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: cpp; gutter: false"&gt;void exception_handler() {&lt;br /&gt;  try {&lt;br /&gt;    if (!std::uncaught_exception()) {&lt;br /&gt;      return; // Nothing to rethrow...&lt;br /&gt;    }&lt;br /&gt;    throw; //rethrow the current exception&lt;br /&gt;  } ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But this does not work: &lt;code&gt;uncaught_exception()&lt;/code&gt; "returns &lt;code&gt;true&lt;/code&gt; after completing evaluation of the object to be thrown until completing the initialization of the exception-declaration in the matching handler", as the standard says.  And when &lt;code&gt;exception_handler&lt;/code&gt; is entered, this is generally from the &lt;code&gt;catch&lt;/code&gt; clause, and the exception has thus been caught...  Your handler would now simply swallow all the exceptions!...&lt;br /&gt;&lt;br /&gt;Actually, &lt;code&gt;uncaught_exception&lt;/code&gt; &lt;a href="http://www.gotw.ca/gotw/047.htm"&gt;is pretty much useless&lt;/a&gt;...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-5344435093602297224?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/5344435093602297224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2010/12/factoring-exception-handling-code-in-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/5344435093602297224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/5344435093602297224'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2010/12/factoring-exception-handling-code-in-c.html' title='Factoring exception handling code in C++'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-1189106912552811930</id><published>2010-12-09T13:31:00.003+01:00</published><updated>2010-12-15T10:57:56.592+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vpn'/><category scheme='http://www.blogger.com/atom/ns#' term='firesheep'/><category scheme='http://www.blogger.com/atom/ns#' term='wifi'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>Using a VPN when connecting to open Wifi networks</title><content type='html'>You may have heard about &lt;a href="http://en.wikipedia.org/wiki/Firesheep"&gt;Firesheep&lt;/a&gt;, a Firefox extension that allows to hijack other people's online accounts.&amp;nbsp; Basically, when you're using an open Wifi hotspot to check your Facebook, Twitter or Gmail[1] account, any other user connected to the same hotspot is able to sniff enough information to impersonate you and connect to your account.&amp;nbsp; Do you really want to risk having your online accounts used by anybody?&lt;br /&gt;&lt;br /&gt;The issue is that although those sites use HTTPS (i.e. secured HTTP) during the login phase, they do not use it for the remainder of the session. And because the Wifi network is not encrypted either, your traffic can be intercepted and read by anyone connected to the same hotspot. This kind of vulnerability, known as &lt;a href="http://en.wikipedia.org/wiki/Session_hijacking"&gt;session hijacking&lt;/a&gt;, exists since a long time, but it is only recently, with the advent of Firesheep, that it received wide coverage.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;What can you do against it?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The simplest is that you stop using open Wifi networks... Pretty useful, no? Ok. Next one...&lt;br /&gt;&lt;br /&gt;In order to prevent session hijacking, you can configure your accounts to always use HTTPS instead of using it only for the login phase.&amp;nbsp; This will encrypt the entire session, preventing attackers to read the cookie that identifies you against the site you're connecting to.&amp;nbsp; This is an option that's &lt;a href="http://mail.google.com/support/bin/answer.py?hl=en&amp;amp;answer=74765"&gt;available for Gmail&lt;/a&gt;, but is not for Facebook or Twitter.&lt;br /&gt;&lt;br /&gt;If you still want to use those sites when on the road, you should use a Virtual Private Network that will encrypt your entire traffic.&amp;nbsp; VPNs are usually set up to allow employees to connect to corporate servers from outside the company's network.&amp;nbsp; Mobile users can thus check their mails, access source code repositories, bug database, etc.&lt;br /&gt;&lt;br /&gt;VPNs can also be used on your home network to gain access to your music or video library, or any other service, in a secure manner.&amp;nbsp; But the trick here will be to allow users connected through the VPN to access the Internet at large, not only your local network.&amp;nbsp; The link from your mobile device to your home server will be protected by the VPN, and the connexion from your home server to the Internet will be assumed to be safe: if you're worried about people who could wiretap your ADSL line, then you should probably not connect any Internet site at all...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Setting up a VPN server&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are tons of tutorials out there about how to configure a PC with any reasonably modern OS to act as a VPN server.&amp;nbsp; Here are some information for &lt;a href="http://theillustratednetwork.mvps.org/Vista/PPTP/PPTPVPN.html"&gt;Windows 7 or Vista&lt;/a&gt; (&lt;b&gt;Start&lt;/b&gt; &amp;gt; &lt;b&gt;Control Panel&lt;/b&gt; &amp;gt; &lt;b&gt;Network and Internet &lt;/b&gt;&amp;gt;&lt;b&gt; Network and Sharing Center&lt;/b&gt;&lt;i&gt; &amp;gt;&lt;/i&gt; &lt;b&gt;Manage network connections&lt;/b&gt;, then hit the &lt;b&gt;Alt&lt;/b&gt; key, choose &lt;b&gt;File&lt;/b&gt; &amp;gt; &lt;b&gt;New Incoming Connection&lt;/b&gt;), &lt;a href="http://www.maclive.net/sid/132"&gt;Mac OS X&lt;/a&gt;, or &lt;a href="http://www.linuxhomenetworking.com/wiki/index.php/Quick_HOWTO_:_Ch35_:_Configuring_Linux_VPNs"&gt;Linux&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Note that, on Windows, you are not offered the possibility to choose your type of VPN service: it's PPTP, and no other.&amp;nbsp; You need to know this when you configure your client...&amp;nbsp; And if you don't have a password on your main account, you must create a new user with a strong password.&lt;br /&gt;&lt;br /&gt;Note also that if you have a router, you'll need to configure it to allow the traffic to come to your VPN server. The tutorial for Windows above has some information about this subject.&lt;br /&gt;&lt;br /&gt;The only issue I had while setting up my Windows 7 box was that you really want to configure it so that IP addresses for incoming connexions use a specify range, with at least two possible addresses...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Setting up your client&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Setting up a server is a necessary step, but you'll also want to configure your mobile device (be it a laptop or a smartphone) to connect to your VPN server.&amp;nbsp; For a Windows client, the 'Connect to a Workplace' wizard will do: Click the &lt;b&gt;Start&lt;/b&gt; button &amp;gt; &lt;b&gt;Control Panel&lt;/b&gt; &amp;gt; &lt;b&gt;Network and Internet&lt;/b&gt; &amp;gt; &lt;b&gt;Network and Sharing Center&lt;/b&gt; &amp;gt; &lt;b&gt;Set up a connection or network&lt;/b&gt; &amp;gt; &lt;b&gt;Connect to a workplace&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;On the iPhone, you have to navigate to Settings &amp;gt; General &amp;gt; Network.&amp;nbsp; Don't worry, it'll be much easier to just turn it on once it's configured... On the lower part of the page, you'll find a button that will allow you to configure a VPN connexion.&amp;nbsp; Here is how I did it:&lt;br /&gt;&lt;br /&gt;&lt;span id="goog_119325521"&gt;&lt;/span&gt;&lt;span id="goog_119325522"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_95_5-qo913g/TQCroegEDFI/AAAAAAAAAJ8/EaF--Bw9QGY/s1600/photo%25282%2529.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/_95_5-qo913g/TQCroegEDFI/AAAAAAAAAJ8/EaF--Bw9QGY/s320/photo%25282%2529.PNG" width="213" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Use the PPTP protocol, with your own (external) IP address, the name of the account you chose when configuring the server, and its password.&amp;nbsp; Make sure 'Send All Traffic' is ON, so that you are really protected!&lt;br /&gt;&lt;br /&gt;You can check your setup is correct by connecting with your iPhone to &lt;a href="http://www.whatsmyip.org/"&gt;a service that shows your IP address &lt;/a&gt;(don't try this from home, it would not prove anything!&amp;nbsp; Or disconnect the Wifi on your iPhone!): it should tell you that your address is the one of your ADSL connection...&lt;br /&gt;&lt;br /&gt;You can now enjoy free Wifi &lt;i&gt;secure&lt;/i&gt; connexions!...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-1189106912552811930?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/1189106912552811930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2010/12/using-vpn-when-connecting-to-open-wifi.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/1189106912552811930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/1189106912552811930'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2010/12/using-vpn-when-connecting-to-open-wifi.html' title='Using a VPN when connecting to open Wifi networks'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_95_5-qo913g/TQCroegEDFI/AAAAAAAAAJ8/EaF--Bw9QGY/s72-c/photo%25282%2529.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-2748824108650317925</id><published>2010-08-26T15:16:00.004+02:00</published><updated>2011-01-05T17:23:00.154+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='relations'/><title type='text'>Implementing One-to-Many Relationships in C++</title><content type='html'>The need to manage relations between objects is at the core of many business applications: objects refer to each other with various semantics, with or without inverse links, for various durations. &lt;br /&gt;&lt;br /&gt;A very common case is the One-to-Many relation: a &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Owner&lt;/span&gt; object has relationships with several &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;User&lt;/span&gt;&amp;nbsp;objects. The owner must know which objects it is related to, and the users have an inverse link to their owner. &amp;nbsp;When a user is added to or removed from its owner, both links should be updated. &amp;nbsp;When the owner is destroyed, all the owned objects are also destroyed. &amp;nbsp;Such relations are extremely common, and often implemented with ad-hoc code.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://xavier.nodet.free.fr/Relations/relations.pdf"&gt;This paper&lt;/a&gt; proposes a set of classes to implement those One-to-Many relations with a minimal amount of code to be written in the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Owner&lt;/span&gt;&amp;nbsp;and &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;User&lt;/span&gt;&amp;nbsp;classes, and performance equivalent to hand-written code, both in terms of memory and CPU.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is an example...&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;#include "relations.h"&lt;br /&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace relations;&lt;br /&gt;&lt;br /&gt;class User;&lt;br /&gt;class Owner;&lt;br /&gt;&lt;br /&gt;class Named {&lt;br /&gt;public:&lt;br /&gt;  Named(const std::string&amp;amp; name) &lt;br /&gt;    : _name(name) {}&lt;br /&gt;  const std::string&amp;amp; name() const {&lt;br /&gt;    return _name;&lt;br /&gt;  }&lt;br /&gt;  ~Named() { &lt;br /&gt;    std::cout &amp;lt;&amp;lt; "Object '" &amp;lt;&amp;lt; _name &amp;lt;&amp;lt; "' destroyed" &amp;lt;&amp;lt; std::endl; &lt;br /&gt;  }&lt;br /&gt;private:&lt;br /&gt;  std::string _name;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class User &lt;br /&gt;  : public RelationUser&amp;lt;Owner, User&amp;gt;&lt;br /&gt;  , public Named {&lt;br /&gt;public:&lt;br /&gt;  User(Owner* owner, const std::string&amp;amp; name)&lt;br /&gt;    : RelationUser&amp;lt;Owner,User&amp;gt;(owner)&lt;br /&gt;    , Named(name)&lt;br /&gt;  {}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class Owner &lt;br /&gt;  : public RelationOwner&amp;lt;RelationUser&amp;lt;Owner, User&amp;gt; &amp;gt; {&lt;br /&gt;public:&lt;br /&gt;  void show();&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void Owner::show() {&lt;br /&gt;  std::cout &amp;lt;&amp;lt; "Users of Owner: ";&lt;br /&gt;  for (Owner::iterator it (begin()); it != end(); ++it) {&lt;br /&gt;    std::cout &amp;lt;&amp;lt; (*it)-&amp;gt;name() &amp;lt;&amp;lt; " ";&lt;br /&gt;  }&lt;br /&gt;  std::cout &amp;lt;&amp;lt; std::endl;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void test()  {&lt;br /&gt;  Owner* owner (new Owner());&lt;br /&gt;  User* user1 (new User(owner, "1"));&lt;br /&gt;  User* user2 (new User(owner, "2"));&lt;br /&gt;  User* user3 (new User(owner, "3"));&lt;br /&gt;  owner-&amp;gt;show();&lt;br /&gt;&lt;br /&gt;  delete user2;&lt;br /&gt;  owner-&amp;gt;show();&lt;br /&gt;&lt;br /&gt;  delete owner; // All users deleted&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;  test();&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;And the output is:&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;Users of Owner: 1 2 3&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;User '2' destroyed&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;Users of Owner: 1 3&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;User '1' destroyed&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;User '3' destroyed&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Enjoy...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-2748824108650317925?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/2748824108650317925/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2010/08/implementing-one-to-many-relationships.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/2748824108650317925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/2748824108650317925'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2010/08/implementing-one-to-many-relationships.html' title='Implementing One-to-Many Relationships in C++'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-7592702655167109716</id><published>2009-11-18T17:30:00.001+01:00</published><updated>2011-01-05T17:30:21.309+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sync'/><category scheme='http://www.blogger.com/atom/ns#' term='xcopy'/><category scheme='http://www.blogger.com/atom/ns#' term='robocopy'/><category scheme='http://www.blogger.com/atom/ns#' term='backup'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>XCopy is failing on you? Use Robocopy!</title><content type='html'>I recently had an issue when trying to backup my data from the laptop to another computer.&amp;nbsp; I was using &lt;a href="http://en.wikipedia.org/wiki/XCOPY"&gt;XCopy&lt;/a&gt;, as usual, to copy all the changed files from a folder and all its sub-folders, so that I keep a mirror of my personal folder on a remote location: all the files that have the 'archive' flag set in this folder (or one of its sub-folders) are copied, and then their flag is reset.&amp;nbsp; Any modification of those files will automatically set the flag, and the files will thus be copied during the next sync.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Recently, all my attempts to use Xcopy on this particular folder were failing with an 'Insufficient memory' error.&amp;nbsp; On a laptop with 4 GB of RAM! It turns out that XCopy still has a limitation from the DOS era: it can't handle full pathnames (location + filename) that are longer than 256 chars! Blah!&lt;br /&gt;&lt;br /&gt;A bit of googling found a possible solution, that turned out to be even more useful than XCOPY, namely &lt;a href="http://en.wikipedia.org/wiki/Robocopy"&gt;Robocopy&lt;/a&gt;.&amp;nbsp; This tool is &lt;a href="http://blogs.msdn.com/matt_pietrek/archive/2007/01/16/robocopy-built-into-vista.aspx"&gt;included into Windows Vista&lt;/a&gt;. It was originally part of the &lt;a class="liexternal" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=9d467a69-57ff-4ae7-96ee-b18c4790cffd&amp;amp;displaylang=en,"&gt;Windows Server 2003 Resource Kit&lt;/a&gt;, but you actually only need the 'robocopy.exe' file, that can be copied onto any Windows NT or Windows XP machine and does not need any installation.&lt;br /&gt;&lt;br /&gt;This tool has options that are the same as the ones from XCopy, and thus allows everything that's possible with the latter.&amp;nbsp; But it can also do much more :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It allows very fine-grained choices of which files to copy, chosen depending on e.g. their attributes;&lt;/li&gt;&lt;li&gt;It knows about the permissions and security access lists attached to the files;&lt;/li&gt;&lt;li&gt;It can move the files, instead of simply copying them;&lt;/li&gt;&lt;li&gt;It can remove files in the destination that are not any more in the source folder ('Mirror' feature).&lt;/li&gt;&lt;/ul&gt;This last feature is the one that convinced me.&amp;nbsp; I can now freely move files around without wondering about the fact that I should delete them from their original location in my mirror. &lt;br /&gt;&lt;br /&gt;Nice tool!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-7592702655167109716?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/7592702655167109716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2009/11/xcopy-is-failing-on-you-use-robocopy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/7592702655167109716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/7592702655167109716'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2009/11/xcopy-is-failing-on-you-use-robocopy.html' title='XCopy is failing on you? Use Robocopy!'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-6835574546499137901</id><published>2009-10-20T14:38:00.003+02:00</published><updated>2011-01-05T17:31:05.212+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>ACCU -- Professionalism in programming</title><content type='html'>If you're serious into programming, you should probably be a member of &lt;a href="http://accu.org/"&gt;ACCU&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;ACCU is an organisation of programmers who care about professionalism in programming and are dedicated to raising the standard of programming. &lt;br /&gt;ACCU publishes &lt;a href="http://accu.org/index.php/aboutus/aboutjournals"&gt;journals&lt;/a&gt;, runs both targeted &lt;a href="http://accu.org/index.php/aboutus/aboutmentoreddevelopers"&gt;mentored projects&lt;/a&gt; and a yearly &lt;a href="http://accu.org/index.php/conferences"&gt;conference&lt;/a&gt;, and hosts &lt;a href="http://accu.org/index.php/mailinglists"&gt;mailing lists&lt;/a&gt; to help programmers develop their skills and professionalism.&lt;br /&gt;&lt;/blockquote&gt;I never had the chance to go to the conference, but the journals are very interesting (Overload is publicly &lt;a href="http://accu.org/index.php/journals/c78/"&gt;available online&lt;/a&gt;).&amp;nbsp; Here is the table of content of &lt;a href="http://accu.org/var/uploads/journals/overload93.pdf"&gt;Overload 93&lt;/a&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The Model Student: A Primal Skyline (Part 2) -- Richard Harris continues investigating the integers’ factors.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Multi-threading in C++0x -- Anthony Williams introduces us to the new threading library.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Quality Matters: Correctness, Robustness and Reliability -- Matthew Wilson defines various measures of quality.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;The Generation, Management and Handling of Errors (Part 2) -- Andy Longshore and Eoin Woods present more error Patterns.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;The mailing lists are also a great source of wisdom.&amp;nbsp; There is a new mentored project that is starting about Patterns, with &lt;a href="http://www.two-sdg.demon.co.uk/curbralan/kevlin.html"&gt;Kevlin Henney&lt;/a&gt; as mentor.&amp;nbsp; Should be great!...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-6835574546499137901?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/6835574546499137901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2009/10/accu-professionalism-in-programming.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/6835574546499137901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/6835574546499137901'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2009/10/accu-professionalism-in-programming.html' title='ACCU -- Professionalism in programming'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-362886846389318485</id><published>2009-09-05T10:39:00.001+02:00</published><updated>2009-10-20T14:43:03.489+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><title type='text'>97 Things Every Programmer Should Know</title><content type='html'>Do you fancy a collection of short essays on programming written by renowed authors: look no further than &lt;a href="http://programmer.97things.oreilly.com/"&gt;97 Things Every Programmer Should Know&lt;/a&gt;.&amp;nbsp; These pearls of wisdom are a must read!...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-362886846389318485?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/362886846389318485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2009/09/97-things-every-programmer-should-know.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/362886846389318485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/362886846389318485'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2009/09/97-things-every-programmer-should-know.html' title='97 Things Every Programmer Should Know'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-6213531648244062027</id><published>2009-08-27T10:45:00.008+02:00</published><updated>2011-01-05T17:31:45.051+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vsprop'/><category scheme='http://www.blogger.com/atom/ns#' term='visual-studio'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='property-sheets'/><title type='text'>A short introduction to VSProps files in Visual Studio</title><content type='html'>Until recently, from the moment I created a second project in my solution, I started muttering against Visual Studio because I had to change the same information in several places to update the configuration of my projects.  Maybe this is over now...&lt;br /&gt;&lt;br /&gt;Suppose you have a Visual Studio solution with several projects : two libraries, a DLL build from them, a few EXE projects to test the DLL.  Suppose the two libraries and the DLL use a third-party library, and you'd like to be able to change the version of this library easily.  Suppose also that you'd like to add pre-compiler definititions to all the projects.&lt;br /&gt;&lt;br /&gt;Visual Studio offers a feature to solve this issue, the &lt;a href="http://msdn.microsoft.com/en-us/library/a4xbdz1e%28classic%29.aspx"&gt;Visual Studio Property Sheets&lt;/a&gt;, or VSProps.  These files are more or less equivalent to the configuration/properties part of the Project files.  You can assign Property Sheets to Projects, and Property Sheets can inherit from other Property Sheets.  Such a tool can greatly ease the management of project configurations in Visual Studio.&lt;br /&gt;&lt;br /&gt;With suitable property sheets, each configuration data appears once: changing the version of the library, or which values are defined, does not require you to change them in each project.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;Creating a Property Sheet&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To create a Property Sheet, choose 'View' -&gt; 'Property Manager'.  Right-click on the project into which you want to add the Sheet, choose 'Add new project property sheet...', and specify a name and a path.&lt;br /&gt;&lt;br /&gt;The new sheet appears as a sub-node in each of the existing configurations.  Right-click one one of those sub-nodes, choose 'Properties', and you are presented with the full dialog that you already know from the properties of a project.&lt;br /&gt;&lt;br /&gt;The values you enter here will be used by any project that uses this property sheet (the first such project being the project into which the sheet was created).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;Inheriting the values of Property Sheet&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you look at the 'General' tab of the project's properties, you will notice the 'Inherited Project Property Sheets' property now has the name of the Property Sheet you just created.  This means that this project uses all the values defined in the property sheet.&lt;br /&gt;&lt;br /&gt;A project may use several property sheets, listed in this field.  The values in the ones listed on the top override, when applicable, those that come from sheets listed below.&lt;br /&gt;&lt;br /&gt;Note that Property Sheets themselves can inherit values from other property sheets.  You can thus build hierarchies of sheets to separate concerns (e.g. one sheet to configure the libraries used in the project, and one other to configure the compiler settings).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;Example: choosing a library version&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Suppose several projects in your solution use a third-party library that's available in two different versions that you wish to support.  Build two separate sheets, one for version X and one for version Y of the third-party library. In each sheet, specify the include path to add and the lib to link with. Name them libX.xml and libY.xml.  Then you build a single property sheet lib.xml that has no configuration value but inherits either from libX.xml or libY.xml.  Let all your projects inherit from lib.xml. The effect is that changing the version of the library only entails changing which sheet lib.xml inherits from.  One change, for the whole solution...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-6213531648244062027?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/6213531648244062027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2009/08/short-introduction-to-vsprops-files-in.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/6213531648244062027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/6213531648244062027'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2009/08/short-introduction-to-vsprops-files-in.html' title='A short introduction to VSProps files in Visual Studio'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1736021189436054208.post-1744177393958408618</id><published>2009-08-20T21:24:00.029+02:00</published><updated>2009-08-23T13:43:36.466+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='routing'/><category scheme='http://www.blogger.com/atom/ns#' term='GPS'/><title type='text'>Finding compromises when planning a route</title><content type='html'>We now have wonderful mapping tools with &lt;a href="http://maps.google.com/"&gt;Google Maps&lt;/a&gt; and the likes, GPS units in our cars, or mapping programs we can install on our computers.  But I've never been really satisfied with those tools when it comes to planning a trip and choosing a route...&lt;br /&gt;&lt;br /&gt;Those tools generally offer control on whether you want the shortest or the quickest route, with or without highways, but that's pretty much all...  Google Maps now offers one or two alternative routes, which is a good step, but I still think it's not enough.&lt;br /&gt;&lt;br /&gt;Let's take an example...  To go from Antibes to Méribel-Les-Allues (in the French Alps, approx 206 km from Antibes on straight line, but with the mountains in between), there are many possible routes.  The shortest one is 385 km, for a duration of 6h49.  The quickest one lasts 5h19, for 566 km.  Most GPS units will be able to give you those two routes, but there are many others...&lt;br /&gt;&lt;br /&gt;Wouldn't it be nice if, after giving those two routes, the unit would ask you if you want to look for a compromise between the two?  This should give you a route that's shorter than 566 km, and quicker than 6h49, if there are some.  It could e.g. give you the route that's 405 km for 5h57.&lt;br /&gt;&lt;br /&gt;Those three routes would be displayed in a table, ordered by distance or by duration, to your choice.  For each couple of consecutive routes, you could ask the unit to look for another compromise between the two selected routes, and this would display a new route in the table, with both the distance and the time in the interval defined by the two previously selected routes.  Or, if there is no such route, this pair would not be selectable any more.&lt;br /&gt;&lt;br /&gt;You would end up with a set of routes that represent different ways to compromise between the two inherently conflicting goals that are distance and duration...  For my example trip, such a table would have entries like : &lt;br /&gt;&lt;br /&gt;&lt;TABLE&gt;&lt;TR&gt;&lt;TD&gt;566 km&lt;/TD&gt;&lt;TD&gt;5h19&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;530 km&lt;/TD&gt;&lt;TD&gt;5h34&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;405 km&lt;/TD&gt;&lt;TD&gt;5h57&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;385 km&lt;/TD&gt;&lt;TD&gt;6h49&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;&lt;br /&gt;&lt;br /&gt;A route that is 512 km and lasts 6h03 would not be displayed: its distance is between the pair 530...405, but it's duration is larger than both: it's clearly not a good compromise in terms of time and distance...&lt;br /&gt;&lt;br /&gt;Of course, the nec-plus-ultra would be to compute the cost of the trip, rather than the distance, taking distance, fuel consumption and tolls into account.  One site I know that computes such costs is &lt;a href="http://www.viamichelin.com/"&gt;ViaMichelin&lt;/a&gt;. In this case, the quickest route costs 98€, and the economical route costs 42€. But am I ready to spend 1h30 more in my car, for a total of more than 7 hours?  Not sure, if the kids are in the car...  And that's when I'd really like to know if there is a route that's much less expensive than the quickest one, for only slightly more time...&lt;br /&gt;&lt;br /&gt;All the data is there...  Why don't we get those informations?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Finding the compromises&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Finding the best route in terms of distance &lt;span style="font-style: italic;"&gt;or&lt;/span&gt; time is known as solving a &lt;a href="http://en.wikipedia.org/wiki/Shortest_path_problem"&gt;Shortest Path Problem&lt;/a&gt;. In our case, we want to simultaneously take into account two conflicting objectives, so we have a &lt;a href="http://en.wikipedia.org/wiki/Multiobjective_optimization"&gt;Multi-Objective&lt;/a&gt; problem. Sophisticated techniques have been devised for such problems, but maybe we can limit ourselves to a simple one...&lt;br /&gt;&lt;br /&gt;Let's suppose that, for each route segment, we know the time and the distance.  We can then compute any combination of the two. Let &lt;span style="font-style: italic;"&gt;x&lt;/span&gt; be a number between &lt;span style="font-style: italic;"&gt;0&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;1&lt;/span&gt;. For each route segment, let's denote &lt;span style="font-style: italic;"&gt;t&lt;/span&gt; the time it takes, and &lt;span style="font-style: italic;"&gt;d&lt;/span&gt; its distance. Instead of either the distance &lt;span style="font-style: italic;"&gt;d&lt;/span&gt; or the time &lt;span style="font-style: italic;"&gt;t&lt;/span&gt;, let's now give, as input to the shortest path algorithm, the value &lt;span style="font-style: italic;"&gt;x.t + (1-x)d&lt;/span&gt;.  For &lt;span style="font-style: italic;"&gt;x=0&lt;/span&gt;, the result is the shortest path.  For &lt;span style="font-style: italic;"&gt;x=1&lt;/span&gt;, the result is the quickest path.  For any value in between, the result is either the shortest path, or the quickest one, or a compromise between both.&lt;br /&gt;&lt;br /&gt;To each value of &lt;span style="font-style: italic;"&gt;x&lt;/span&gt;, we can thus associate a route.  The unit first computes the routes for for &lt;span style="font-style: italic;"&gt;x=0&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;x=1&lt;/span&gt;. When the user asks for a compromise between two routes, those two routes define the interval &lt;span style="font-style: italic;"&gt;x1..x2&lt;/span&gt; that the unit must explore with a dichotomy.  We start with &lt;span style="font-style: italic;"&gt;(x1+x2)/2&lt;/span&gt;, and see which route this gives.  If it's the same than for &lt;span style="font-style: italic;"&gt;x1&lt;/span&gt;, we know that the compromize we want, if it exists, is between &lt;span style="font-style: italic;"&gt;(x1+x2)/2&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;x2&lt;/span&gt;.  If it's the same than for &lt;span style="font-style: italic;"&gt;x2&lt;/span&gt;, we know that we have to look between &lt;span style="font-style: italic;"&gt;x1&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;(x1+x2)/2&lt;/span&gt;.  If it's neither, then we've just found a new route that we can display to the user.  If the interval between the two values becomes too small, then we can stop the search and notify that it was not possible to find a compromise between the two routes.&lt;br /&gt;&lt;br /&gt;Pretty simple, no?&lt;br /&gt;&lt;br /&gt;And given the fact that recent computers can compute routes between any two points on a continent in around 1/10th of a second, it should be possible to answer in less than one second for each compromize sought...  A GPS unit would probably need more time, but only the users willing to wait would have to...&lt;br /&gt;&lt;br /&gt;In a few seconds, the user would get a list of possible compromise, and would be in the position to choose with much more informations...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1736021189436054208-1744177393958408618?l=xnodet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnodet.blogspot.com/feeds/1744177393958408618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://xnodet.blogspot.com/2009/08/finding-compromises-when-planning-route.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/1744177393958408618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1736021189436054208/posts/default/1744177393958408618'/><link rel='alternate' type='text/html' href='http://xnodet.blogspot.com/2009/08/finding-compromises-when-planning-route.html' title='Finding compromises when planning a route'/><author><name>Xavier Nodet</name><uri>http://www.blogger.com/profile/01035691436150525152</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-74wamyya6iA/Ttpv2sMTteI/AAAAAAAAAK8/sXXTZRRhAYU/s220/IMG_4733.JPG'/></author><thr:total>0</thr:total></entry></feed>
