Taoffi's blog

prisonniers du temps

Deep Zoom follow-up - optimizing displayed (KML) polygon points

DeepZoom has been one of the most inspiring projects/technologies in last years. Its approach is now extensively used in various domains, notably in mapping applications.

I think DeepZoom approach still have more application areas to explore.

In this article, I will explore one question where the DeepZoom approach can be quite useful.

KML Polygons

KML (Keyhole Markup Language) is an XML-notation-based 'language' now widely used to describe geographic data. Among many types of data, KML includes Polygons, which describe point locations on a map. A polygon may, for instance describe the contour of political frontiers of a country or a seashore…, which may thus contain a large number of point-coordinates.

As each of the polygon's points may be associated with more or less large data objects, processing the polygon information may become a challenging operation either on a server or on a client machine. Reducing manipulated polygon data size and required processing efforts is thus an important performance question.

One of the techniques often used is to compress (zip) the KML transmitted files' data (to produce .kmz files instead of .kml). But there should be a better approach in simply transferring (or processing) only significant point's data.

 

Zoom level and view port

When we view or display a map, we in fact view in a zoom level. According to this zoom level, two points may have a significant distance or be confused into one same point.

The following figures illustrate this:

  • At the first zoom level, point 1 and point 2 are clearly distinct
  • The more we zoom-out, the less distinctive they become
  • Until both can be considered as one same point

Conclusion: according to the zoom-level, we may transfer (or manipulate/process) only one of those points instead of both.

 

Zoom level1

Zoom-out1

Zoom-out2

 

This can also be illustrated by the DeepZoom 'pyramid' approach:

 

 

A map is also viewed into a 'View Port' (the window through which we view the map).

For the two points of the previous example, at certain zoom-in level (or view port coordinates change), one (or both) of them may be located out of the view port.

 

 

Another conclusion: we don't need to transfer (or manipulate/process) polygon points which may be located outside of the current view port.

The delivered code sample

The downloadable code includes the data of a polygon composed of a large array of points.

The sample uses several parameters to determine which points to be considered for transfer or processing:

  • The view port coordinates: used to select only points inside the view port
  • The zoom level: associated with a ratio used to compare the significance of points' coordinates variations

 

The ZoomPortView object exposes few properties: a Name, a ZoomRatio, TopLeft and BottomRight points (Width and Height are calculated according to those points' coordinates).

 

The ZoomPolygon object exposes few properties: a list of polygon's Points. For the sake of current demonstration, the object also exposes PointsOutOfPortView which is a list of points that are out of the current port view.

ZoomPolygon class offers a static method which parses an array of points according to a given port view, returning the related new ZoomPolygon object.

 

public static ZoomPolygon Parse(Point[] points, ZoomPortView portView)
{
    ZoomPolygon        polygon        = new ZoomPolygon(portView);
    ObservableCollection<Point> pointList = new ObservableCollection<Point>();
    ObservableCollection<Point> pointsOutPortView = new ObservableCollection<Point>();
    double    zoomRatio = portView.ZoomRatio;
 
    double maxX    = portView.Width,
            maxY    = portView.Height;
    Point    point,
            last    = new Point();
 
    for(int index = 0; index< points.Length; index++)
    {
        point = points[index];
 
        if( ! portView.IsPointInPortview(point))
        {
            pointsOutPortView.Add(point);
            goto next_point;
        }
 
        if (pointList.Count <= 0)
        {
            pointList.Add(point);
            goto next_point;
        }
 
        if( Math.Abs( (point.X - last.X) / maxX) >= zoomRatio
            || Math.Abs( (point.Y - last.Y) / maxY) >= zoomRatio)
            pointList.Add(point);
next_point:
        last = point;
    }
 
    polygon.Points = pointList;
    polygon.PointsOutOfPortView = pointsOutPortView;
    return polygon;
}
 

 

Note: the code above can of course be more compact using Linq. This version seems more illustrative of the logic to include / exclude polygon points.

 

Sample screen shots

 

Download the sample code

KmlOptimizerSample.zip (1.28 mb)

Acknowledgement

Thanks to all my friends at Thomson Reuters' iMap Project with whom I learnt much about kml and maps in general: Benoît, Florent, Catalin, Christophe, Ronan, John, Geffe, Calum…

Choices in a logical tree view – WPF sample

Using check boxes in TreeView control is a handy way for presenting choices in their logical tree-like structure.

In real life, though, choices can be a mix of inclusive (check-box) and exclusive (radio-button) options.

I expose here a solution for using that mix of option types in one same tree view.

The problem

The problem is divided into three main subjects:

  • How to use a mix of checkbox / radio button nodes in the same tree view control
  • How to get a radio button to be toggled from checked to unchecked status: Checkboxes are, 'naturally', able to be toggled from checked to unchecked status. This is not the case for Radio buttons. The result is that when you use radio button in a tree view, you will be able to check it but not to get it uncheck!
  • How to handle exclusive choices selection. That is when an exclusive option gets selected (checked), for instance,we must unselect all other exclusive sibling options.

 

To solve the first question, we will use:

  • A tree node object which indicates its option type (exclusive / inclusive)
  • Hierarchical control templates for each choice type
  • A template selector which will select the correct template according to the node object choice type

 

To solve the second, we will simply create a new Toggled Radio Button (which derives from RadioButton) and get this new object handle the Click event to toggle its selection status.

 

 

public class RadioToggleButton : RadioButton
{
    protected override void OnClick()
    {
        IsChecked = !IsChecked;
    }
}

 

 

The third question will be solved by implementing the required behaviors within our special tree node object.

 

The TreeNode object

The TreeNode object exposes few properties:

  • A Title
  • A Parent node (TreeNode)
  • A list of Children (List of TreeNode items)
  • A boolean flag which indicates if the node represents an exclusive choice option
  • A boolean flag which indicates if the node is selected

Through these properties, TreeNode object can expose other properties like its Root node, the First exclusive parent or descendant… etc.

 

The TreeNode Hierarchical data template

 

<UserControl.Resources>
…
…
    <!-- hierarchical template for checkbox treeview items -->
    <HierarchicalDataTemplate x:Key="checkBoxTemplate" 
        DataType="{x:Type app:TreeNode}"
        ItemsSource="{Binding Children}">
        <StackPanel Orientation="Horizontal">
            <CheckBox Focusable="False"
                VerticalAlignment="Center"
                IsChecked="{Binding IsSelected, Mode=TwoWay}" />
            <TextBlock Text="{Binding Title}" />
        </StackPanel>
    </HierarchicalDataTemplate>
 
    <!-- hierarchical template for (toggled) radio buttons treeview items -->
    <HierarchicalDataTemplate x:Key="radioButtonTemplate" 
            DataType="{x:Type app:TreeNode}"
            ItemsSource="{Binding Children}">
        <StackPanel Orientation="Horizontal">
            <ctrl:RadioToggleButton Focusable="False"
            VerticalAlignment="Center"
            IsChecked="{Binding IsSelected, Mode=TwoWay}" />
            <TextBlock Text="{Binding Title}" Margin="4, 1, 0, 0" />
        </StackPanel>
    </HierarchicalDataTemplate>
</UserControl.Resources>

 

 

The TreeView node's Item template selector

 

public class TreeNodeXTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(
                object item, DependencyObject container)
    {
        FrameworkElement    element = container    as FrameworkElement;
        TreeNode    node    = item  as TreeNode;
 
        if (element != null && node != null)
        {
            if (node.IsExclusive)
                return element.FindResource("radioButtonTemplate")
                                 as HierarchicalDataTemplate;
            return element.FindResource("checkBoxTemplate")
                                as HierarchicalDataTemplate;
        }
        return null;
    }
}

 

 

We can now use an ItemTemplateSelector to tell the Tree view control to select the adequate data template for each item according the tree node choice selection type (exclusive / inclusive)

 

<UserControl.Resources>
    <app:TreeNodeXTemplateSelector	x:Key="templateSelector" />
    …
    …
</UserControl.Resources>

 

<TreeView x:Name="treeview1" ItemsSource="{Binding Root.Children}"
                  ItemTemplateSelector="{StaticResource templateSelector}"/>

 

 

Exclusive node selection behavior

TreeNode selection behavior can be summarized as follows:

  • If the node is inclusive: do nothing (just set the selected flag)
  • If the node is exclusive (and selected):
    • Unselect all exclusive siblings (siblings = Parent's Children)
    • Select all inclusive child nodes
    • Select the first exclusive child node if any

 

public void UpdateSelection()
{
    if(! _isExclusive)
        return;
 
    if(_isSelected == true)
    {
        UnSelectSiblings();
    }
 
    SelectChildren(_isSelected);
}

 

 

 

protected void SelectChildren(bool selected)
{
    if(! selected)
    {
        UnSelectChildren();
        return;
    }
 
    TreeNode firstEx = FirstExclusiveChild;
 
    if(firstEx != null)
        firstEx.IsSelected = selected;
 
    foreach(TreeNode node in _children)
    {
        if(node.IsExclusive)
            continue;
 
        node.SetSelection(value: selected, updateChildren: true);
    }
}

 

 

Sample screenshot

 

Download the sample code TreeViewRadioAndCheckButtons.zip (67.88 kb)

Meta-models: towards a universal dependency injection framework

Intro

I joined an interesting presentation today about unit tests. Part of the presentation was related to dependency injection usage for unit testing. That brought to my mind again the benefits of meta-models.

The problem

Unit testing often faces the problem of having to instantiate objects that may impact the test itself or simply make the test impossible.

A sound example of this is when the method to be tested requires the instantiation of an object requiring, for instance, a database connection.

In this schema, we have 3 actors

  • The function
  • The caller
  • The object (SomeObject) which cannot be instantiated.

 

Traditional recipe

One, now traditional, recipe is to use an Interface (instead of the specific object) as a function parameter. And, according to the context, instantiate and use an object that implements the defined interface. The figure below illustrates this.

 

Good solution… a little acrobatic, but OK… good.

 

A problem, though. We now have 6 actors (to code and maintain):

  • The Function
  • The caller
  • The original 'true' object (SomeObject)
  • The Interface
  • The interface implementations (=2)!

 

On the other hand, testing a function may also need to instantiate a 'true' object context. In which case, we would have to rewrite (and recompileJ) our test code to instantiate a 'true' implementation when required.

A third point: in this solution, we defined the Interface to represent an abstraction of the original object. What if the original object itself was, for instance, a database record? This would then introduce a new actor in our playgroundJ

 

As Bjarne Stroustrup puts it:

"Any verbose and tedious solution is error-prone because programmers get bored" J

 

Meta-models may be a better way

In the current case, meta-models (see my previous posts) can be used to more simply describe all actors (object structures / methods / properties…).

An illustration:

 

 

Reminder: meta-models are closely related and enforced by Reflection (assemblies' meta-data). Through meta-models AND Reflection (namespace System.Reflection) developers can gain more flexibility to create versatile and scalable software.

 

In our present case, meta-models not only expose less actors to code and maintain, but also lower the complexity level of involved actors (for instance: maintaining database records instead of hard coding implementation).

 

The main goal for this approach is to ultimately write fewer universal methods to invoke and instantiate any object!

Will try to deliver a code sample in a future post. In the meantime, you may download meta-model sample code here!

TFS database pause: Change set quantitative statistics sample

Where to find change-sets information?


TFS source control maintains change-sets for projects in the corresponding collection database. Each change-set is of course composed of the modified project files at the time of the Check-in.

Change-set information is stored in the tbl_ChangeSet table of the project collection database. That is: if you have a project collection 'Default Collection' stored in a database named tfs_default_collection, you will find change-sets information in the table tfs_default_collection.dbo.tbl_ChangeSet.

Files information is stored in tbl_files table, and file-versions information in tbl_Version table.

So, to obtain the list of files of a change-set number 861, for instance, you can execute a query similar to the following:


SELECT TOP (100) percent
    chg_set.CreationDate,
    chg_set.ChangeSetId,
    v.FullPath

FROM
    dbo.tbl_ChangeSet (nolock)AS chg_set INNER JOIN
    
dbo.
tbl_Version (nolock)AS v ON chg_set.ChangeSetId = v.VersionFrom LEFT OUTER JOIN
    
dbo.
tbl_File (nolock) AS f ON v.FileId = f.FileId


WHERE (chg_set.ChangeSetId = 861)

ORDER BY chg_set.CreationDate, v.FullPath

 

 

Which may produce results like the following:

CreationDate

ChangeSetId

FullPath

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\commands\UniConvertCommandModel.cs\

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\Convert.xaml\

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\MainWindow.xaml.cs\

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\MainWindow.xaml\

 

How many bytes changed?


As you may have noticed from the figure above, change-set file information contains a FileLength column. This suggests that we can obtain the number of changed bytes of a given file between two change-sets… through the following query results we can know that the file grew 696-551 = 145 bytes:

CreationDate

ChangeSetId

FullPath

FileLength

2012-04-30 22:33:10.040

843

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

551

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

696

 

Who changed what?


The change-set table provides an CommitterId column through which we can know who made a given check-in. As this column contains an ID (integer refering tbl_identity.IdentityId), this is not straight forward information. We have to join other tables to obtain something useful.

In fact, the committer user name is stored in the Constants table. So, we have to join the Change-set's CommitterId column to tbl_identity.IdentityId, and then join tbl_identity.TeamFoundationId to Constants.TeamFoundationId… we can then get the user name in the Constants.DisplayPart column (or Constants.String column)

 

 

This can be presented by the following change in our initial view diagram:

 

CreationDate

ChangeSetId

FullPath

FileLength

DisplayPart

2012-04-30 22:33:10.040

843

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

551

Taoffi

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

696

Taoffi

 

Changed bytes tracking generalization


It would, ideally, be beneficial to integrate such information into the TFS analytical database.

We still can do some turnaround by directly querying the database tables.

The idea is to list all change-set files in the order of their respective check-in date. To handle the probability of identical dates / files, we can use a row number to distinguish changes. This may be done like in the following view:


CREATE VIEW [dbo].[xtfs_changeset_files_qry]
AS
SELECT
TOP (2147483647)
    ROW_NUMBER() over( ORDER BY chg_set.CreationDate) as row_number,
    chg_set.CreationDate,

    const.DisplayPart        as user_name,
    chg_set.ChangeSetId,

    v.FullPath,
    f.FileLength

FROM dbo.tbl_ChangeSet (nolock)    AS chg_set INNER JOIN
dbo.tbl_Identity (nolock)    AS login ON chg_set.CommitterId = login.IdentityId INNER JOIN
dbo.tbl_Version (nolock)    AS v ON chg_set.ChangeSetId = v.VersionFrom LEFT OUTER JOIN
dbo.tbl_File (nolock)        AS f ON v.FileId = f.FileId inner join
Constants (nolock)        AS const ON const.TeamFoundationId=login.TeamFoundationId

ORDER
BY chg_set.
CreationDate, v.FullPath


GO

 

We can then refer the view to itself (current version / previous version) obtain row-relative quantitative changes:

SELECT v1.row_number,
       v1.CreationDate,
       v1.user_name,
       v1.FullPath AS v1FilePath,
       v1.FileLength AS v1_length,
       v_next.FileLength AS v2_length,
       v_next.FullPath AS v2FilePath,
       ISNULL(v_next.FileLength, 0)
          - ISNULL(v1.FileLength, 0) AS changed_bytes

FROM dbo.xtfs_changeset_files_qry AS v_next RIGHT OUTER JOIN
     dbo.xtfs_changeset_files_qry AS v1 ON v_next.FullPath = v1.FullPath
        AND v_next.row_number = v1.row_number + 1
        OR v_next.FullPath IS NULL
        AND v_next.row_number IS NULL

 

A dive into the undocumented TFS meta-model – Part I

TFS… introduction to this series


Microsoft TFS (Team Foundation Server… recently renamed to ALM: Application Lifecycle Management) is a great project management platform.

TFS is built on meta-model abstractions (that were first seen, in Microsoft's products, in SharePoint).

TFS, like SharePoint, is composed of several software components which operate around several databases: the configuration database and one or more content databases.

Configuration and content databases' elements (tables, views, functions, stored procedures… etc.) represent the meta-models (schemas and business logic for each related feature) which govern and control much of the software components' behaviors.

TFS is often presented as a software project management solution. In my view, this seems a little reductive of its value. Because TFS features truly span a much larger project management scope.

Many useful literatures have been written about TFS: its features, usage, guidance, troubleshooting… etc. Few have enlightened its meta-model structures and, as of my knowledge, none has put some clear light about its (undocumented) databases' structures. That is what I will try to do in this series, more to value TFS abstractions than to nude its internal mechanics. And also to enforce, again, the meta-model approach as a rational basis for software solutions.

 

TFS logical architecture

 

For its contents, TFS maintains a database per project-collection.

Each collection may contain one or more projects. And each project can be managed according to a selected methodology (Agile / Scrum / CMMI… etc.). In fact, TFS applies and operates the selected methodology through the provided methodology project management template. Ultimately, this means you can build your own methodology and use it to manage your project with TFS. All what you need is to provide the desired methodology template.

Managing a project with TFS consists of recording and following-up specific Work items (defined by the methodology template)… those can be items like: Tasks, Bugs, Change requests, User story… etc.

As TFS was initially brewed to manage software projects, a common item in each project is the Source control repository which helps developers to maintain their source code versions and branches in a very efficient architecture composed of 'change sets'.

 

 

To discover and figure out its components' data and their required behaviors, TFS uses a configuration database. A first look at the configuration database will be the subject of this first article in the series.

 

The configuration database


Like SharePoint, TFS databases are delivered without documentation or relational diagrams. They simply don't contain any explicit Foreign-keys or relationships. Whatever the reason behind this choice, that seems a little surprising of a product whose main aim is projects' transparency and documentationJ.

That said, to discover, understand and correctly interpret the role of each TFS database item and their inter-relationships you should do a deep dive and be armed with some patience and empiric methods!

 

Hosts and processes


Let's have a look at three important tables:

  • tbl_ServiceHost contains the list of services' host information. This includes the item's name, the database connection string (when relevant), the Virtual directory and Resource directory…
  • tbl_ServiceHostProcess contains information about current processes. Machine name, Process name, Identity under which the process is running, start time…
  • tbl_ServiceHostInstance contains the list of processes' instances per host (Process Id / Host Id / Start time).

 

In my case, the table tbl_ServiceHost contained 3 entries for:

  • Team Foundation: root item (parentless… see diagram ParentHostId column). Connected to the configuration database.
  • Two child entries each for one of my TFS Project collections:
    • Default collection.
    • Training collection.

 

The above relational schema allows us to query the tables and obtain results like the following about current running services:


SELECT TOP (100) PERCENT
svcHost.Name         AS host,
svcHost.VirtualDirectory,
svcHost.ConnectionString,
process.MachineName    AS machine,
process.ProcessName,
process.StartTime


FROM dbo.tbl_ServiceHostInstance AS instance INNER JOIN
dbo.tbl_ServiceHost AS svcHost ON instance.HostId = svcHost.HostId LEFT OUTER JOIN
dbo.tbl_ServiceHostProcess AS process ON instance.ProcessId = process.ProcessId LEFT OUTER JOIN
dbo.tbl_ServiceHost AS hostParent ON svcHost.ParentHostId = hostParent.HostId

ORDER BY process.StartTime DESC, hostParent.Name, host

 

Sample results

host 

VirtualDirectory 

ConnectionString 

machine

ProcessName 

StartTime 

TEAM FOUNDATION 

NULL 

Data Source= hp10\SqlTfs;Initial Catalog=Tfs_Configuration;Integrated Security=True

HP10 

w3wp.exe 

2012-05-21 20:18:09.997 

DefaultCollection 

~/DefaultCollection/ 

Data Source=hp10\sqltfs;Initial Catalog=tfs_defaultcollection;Integrated Security=True 

HP10 

w3wp.exe 

2012-05-21 20:18:09.997 

Training collection 

~/Training collection/ 

Data Source=hp10\SqlTfs;Initial Catalog="Tfs_Training collection";Integrated Security=True

HP10 

w3wp.exe 

2012-05-21 20:18:09.997 

TEAM FOUNDATION 

NULL 

Data Source=hp10\SqlTfs;Initial Catalog=Tfs_Configuration;Integrated Security=True 

HP10 

TfsJobAgent.exe 

2012-05-21 06:51:37.870 

DefaultCollection 

~/DefaultCollection/ 

Data Source=hp10\sqltfs;Initial Catalog=tfs_defaultcollection;Integrated Security=True 

HP10 

TfsJobAgent.exe 

2012-05-21 06:51:37.870 

Training collection 

~/Training collection/ 

Data Source=hp10\SqlTfs;Initial Catalog="Tfs_Training collection";Integrated Security=True

HP10 

TfsJobAgent.exe 

2012-05-21 06:51:37.870 

 

Ressources and services

Again, let's follow up the following tables:

  • tbl_CatalogResourceType stores a list of resource types. Like: 'Machine', 'Infrastructure Root', 'Project Server', 'Team Foundation Project Collection Database'… etc. Here is some sample entries:

Identifier 

DisplayName 

Description 

9FB288AE-9D94-40CB-B5E7-0EFC3FE3599F 

Default location for team project portals 

By default, each team project Web site will be a sub-site of this location.

0584A4A2-475B-460E-A7AC-10C28951518F 

Machine 

A machine that exists as part of the TFS deployment. 

14F04669-6779-42D5-8975-184B93650C83 

Infrastructure Root 

The root of the catalog tree that describes the physical makeup of the TFS deployment.

1B6B5931-69F6-4C53-90A0-220B177353B7 

Team Foundation Project Collection Database 

The database that houses the information for a Team Foundation Project Collection. 

526301DE-F821-48C8-ABBD-3430DC7946D3 

Team Foundation Configuration Database

The database that houses the information for a Team Foundation Application Instance. 

289DD275-CECA-4698-8042-38D2E86FC682 

Project Server 

Project Server Information 

3DADD190-40E6-4FC1-A306-4906713C87CE 

SharePoint Web Application 

A SharePoint Web application that has been configured to support team project portals.

3C856555-8737-48B6-8B61-4B24DB7FEB15 

Test Controller 

This is a test controller type in Catalog Service. 

26338D9E-D437-44AA-91F2-55880A328B54 

Team Project Collection 

A Team Project Collection that exists within the TFS deployment.

450901B6-B528-4863-9876-5BD3927DF467 

Project Portal 

A Web site or SharePoint site that provides a portal for a team project. 

15DA1594-45F5-47D4-AE52-78F16E67EB1E 

Process Guidance 

A Web site or SharePoint library that provides process guidance for a team project.

47FA57A4-8157-4FB5-9A64-A7A4954BD284 

Team Web Access 

Team Web Access Location 

48577A4A-801E-412C-B8AE-CF7EF3529616 

Team Project 

A Team Project that exists within the TFS deployment. 

 

  • tbl_CatalogResource stores resources (each referring to one of the types in the above tbl_CatalogResourceType table. Sample entries:

 

Identifier 

ResourceType 

DisplayName 

Description 

7462A882-741B-4F91-885F-1405A22256DF 

1B6B5931-69F6-4C53-90A0-220B177353B7 

Tfs_Training collection

 

C5CD36C5-8373-4BF7-B3FA-16199DAFF106 

48577A4A-801E-412C-B8AE-CF7EF3529616 

cmmi project 

cmmi training project 

16480162-C502-4197-872A-4DDDFE49BA90 

1B6B5931-69F6-4C53-90A0-220B177353B7 

tfs_defaultcollection 

 

DCC270E7-6EC7-45BF-A827-53BBB5386606

14F04669-6779-42D5-8975-184B93650C83 

Infrastructure Root 

The root of the catalog tree that describes the physical makeup of the TFS deployment. 

2F8C7D1C-EB1F-4058-B34D-60FA2F6CA7DC 

48577A4A-801E-412C-B8AE-CF7EF3529616 

Agile project 

 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7

47FA57A4-8157-4FB5-9A64-A7A4954BD284 

Team Web Access 

 

4B812279-A7A6-4A8A-92A4-7AA208589FEB 

EB1E0B3B-FAA1-49D2-931A-FDC373682BA5 

SQLTFS 

 

F69EFD2B-51C6-461B-9E49-8089DF86C9A3 

0584A4A2-475B-460E-A7AC-10C28951518F 

hp10 

 

5242DBFC-06C8-4CAD-A27B-99212BEEE999

526301DE-F821-48C8-ABBD-3430DC7946D3 

Tfs_Configuration 

 

713FF18A-E0E8-4192-A7B9-A0900F50A5BC 

26338D9E-D437-44AA-91F2-55880A328B54 

DefaultCollection 

 

 

  • tbl_ServiceDefinition stores a list of predefined services (classes) and the web access page for each. Sample entries (among other things, you may note curly braces which are place holders for some url parameters in the RelativePath column):

 

ServiceType 

Identifier 

DisplayName 

RelativePath 

AdministrationService 

C18D6E34-68E8-40D2-A619-E7477558976E

Administration Service 

/TeamFoundation/Administration/v3.0/AdministrationService.asmx 

Annotate 

74B15E02-0AC2-414F-A9B9-30268659D3B5 

Team Web Access (Annotate) 

/web/ann.aspx 

AnnotateSourceControlItem

D271E722-C261-4BC2-B0F7-1C8A9E13F907 

Team Web Access (AnnotateSourceControlItem) 

/web/ann.aspx?pcguid={projectCollectionGuid}&path={itemPath}&cs={itemChangeset} 

CatalogService 

C2F9106F-127A-45B7-B0A3-E0AD8239A2A7 

Catalog Service 

/TeamFoundation/Administration/v3.0/CatalogService.asmx

ChangesetDetail 

D40EF625-CCA7-4E73-B9EC-86CBE1534CE0 

Team Web Access (ChangesetDetail) 

/web/cs.aspx 

CreateWorkItem 

14CD69C6-88F9-4C8C-A259-D2441D77D1AF

Team Web Access (CreateWorkItem) 

/web/wi.aspx?puri={projectUri}&wit={workItemType} 

Difference 

2B84D900-1F08-486C-9C47-0E6AF371D03C 

Team Web Access (Difference) 

/web/diff.aspx 

Eventing 

C424AE04-8C6F-4516-8B2D-238FFFCA3081 

Event Service 

/TeamFoundation/Administration/v3.0/EventService.asmx

IdentityManagementService 

3DE26348-00BE-4B82-8E4A-E5AD004CFECD 

Identity Management Service 

/TeamFoundation/Administration/v3.0/IdentityManagementService.asmx 

JobService 

DA1C0184-14FE-4E13-B7FC-6EAA07D84BE8 

TFS Background Job Service 

/TeamFoundation/Administration/v3.0/JobService.asmx 

 

  • tbl_CatalogServiceReference stores per-resource services' entries. (Resource Identifier / Service Identifier…).

 

ResourceIdentifier 

AssociationKey 

ServiceIdentifier 

ServiceType 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

ChangesetDetail 

D40EF625-CCA7-4E73-B9EC-86CBE1534CE0

ChangesetDetail 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

CreateWorkItem 

14CD69C6-88F9-4C8C-A259-D2441D77D1AF 

CreateWorkItem 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

Difference 

2B84D900-1F08-486C-9C47-0E6AF371D03C 

Difference 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7

DiffSourceControlItems 

5E91C4DA-0013-4EBB-943D-CC77F5ADB82D 

DiffSourceControlItems 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

DiffSourceControlShelvedItem 

4C81A44D-67AB-4D23-9CBE-339C9102993B 

DiffSourceControlShelvedItem 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

ExploreSourceControlPath

AC0770BC-1DD6-4B8E-A811-5A03690DF44F 

ExploreSourceControlPath 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

Home 

0F9CED5D-89F9-4743-BAB8-FA511FF09A8C 

TSWAHome 

 

This allows us to query the services in a way similar to the following:

SELECT resType.DisplayName AS ResourceType,
svc.DisplayName AS Service,
svc.Description AS serviceDescription
FROM dbo.tbl_ServiceDefinition AS svc INNER JOIN
dbo.tbl_CatalogServiceReference AS svcRef ON svc.Identifier = svcRef.ServiceIdentifier
INNER JOIN
dbo.tbl_CatalogResource AS Res ON svcRef.ResourceIdentifier = Res.Identifier
INNER JOIN
dbo.tbl_CatalogResourceType AS resType ON Res.ResourceType = resType.Identifier

 

 

Sample results:

ResourceType

Service

serviceDescription

Team Web Access

Team Web Access (Annotate)

 

Team Web Access

Team Web Access (AnnotateSourceControlItem)

 

Team Web Access

Team Web Access (ChangesetDetail)

 

Team Web Access

Team Web Access (CreateWorkItem)

 

Team Web Access

Team Web Access (Difference)

 

Team Web Access

Team Web Access (DiffSourceControlItems)

 

Team Web Access

Team Web Access (DiffSourceControlShelvedItem)

 

Team Web Access

Team Web Access (DiffSourceControlShelvedItem)

 

Team Web Access

Team Web Access (ExploreSourceControlPath)

 

Team Project Collection

Location Service

Location Service for Visual Studio Team Foundation Server.

Team Project Collection

Location Service

Location Service for Visual Studio Team Foundation Server.

Team Foundation Server Instance

Location Service

Location Service for Visual Studio Team Foundation Server.

Team Web Access

Team Web Access (OpenWorkItem)

 

 

More about TFS meta-models in following posts!

WPF and a ComboBox dilemma (again!)

Sometime ago, I discussed a ComboBox mouse scroll issue in Silverlight. I, again, had a new problem with the ComboBox control… this time in a WPF application.

The ItemsSource update problem

In my case, I had a ComboBox whose ItemsSource was bound to a list of items which was updated dynamically, and its SelectedItem bound to one item of the list. The problem was that the ComboBox was correctly updating the SelectedItem, while the drop-down list continued to display the older list of items! ... Here is a sample illustration:

 

Figure 1: This is the first context:

 

Figure 2: The item list changed… the ComboBox correctly displays the selected item (2.476563)… which doesn’t exist at all in the items list. The drop-down list still displays the old items list!

 

Such odd situations make you feel that either there should be an error somewhere in your code… or that the CombBox itself is a control that you should reinvent yourself!

 

Check your code!

Here is my Xaml code… that really seems so ‘standard’


<ComboBox x:Name="combobox_rates"
    ItemsSource="{Binding Combinations, Mode=OneWay}"
    SelectionChanged="combobox_rates_SelectionChanged"
    Height="24"
    Width="280"
    ItemTemplate="{DynamicResource combi_list_template}"
    SelectedItem="{Binding Path=SelectedCombination}" />

According to someone advice, let-s add a IsSynchronizedWithCurrentItem=”True”:


<ComboBox x:Name="combobox_rates"
    IsSynchronizedWithCurrentItem="True"
    

Desperately, that doesn’t solve the problem!
Another advice: Bind the ItemsSource to an ObservableCollection<T> (instead of a List<T>): nothing changes…
A third one: add an UpdateSourceTrigger=PropertyChanged to the Binding… let’s just try

ItemsSource="{Binding Combinations, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"

 

The solution

Still, we didn’t try this… let’s use the IsAsync Binding attribute:

ItemsSource="{Binding Combinations, IsAsync=True, Mode=OneWay}"

Oh… that seems to work great!
Is sofware development a Science, an Art, or Craftsmanship?!

Back to earth: DBNull and ConetxtMenuStrip target TreeView node

 

It is time now to set concepts aside for some more practical problems!

Last days, through the work on two different projects, I encountered DBNull twice, and faced a funny problem about locating the target TreeNode of a contextual menu!

Let us start by the first one:

DBNull in Silverlight and Windows Forms

I encountered a DBNull problem two times (in three days… that seems a bit much). The first time was in the context of a WCF service intended to feed a Silverlight application, and the second was in the context of a GridView control in a Windows Forms application.
For your information, DBNull is a .NET Type defined in namespace System (mscorlib.dll).

The first issue emerged with what appeared to be a communication problem between a Silverlight application and one related WCF service. After some research, DBNull was reported to be an unknown Type in XML serialization. The service was transmitting data read through a SQL Server database… We had a Cell class. Its Data member was an object.
A bit more research made it visible that the following code as the source of the annoyance:

cell.Data = data_reader.GetValue(cell_index)

 

In fact, when the field at cell_index was null, data_reader.GetValue() returned DBNull. Which was assigned as the cell’s Data. Serialized by WCF, DBNull was not recognized by the receiving Silverlight application.

Though the time needed to discover the source of the problem was quite long, the solution was quite simple:

 

cell.Data = data_reader.IsDBNull(cell_index)

                  ? null :data_reader.GetValue(cell_index)

// Which clearly means:

if(data_reader.IsDBNull(cell_index))

    cell.Data = null;

else

    cell.Data = data_reader.GetValue(cell_index)

Now that the cell content is null, everything goes right (because null is a recognize Type).
It will be a great day when DBNull (which implements the ISerializable Interface) will simply be serialized as null… let us just wait.

Yet another DBNull problem!

Once the Silverlight DBNull problem solved… precisely: the next day J, I just found myself again confronted by another DBNull. This time in a Windows Forms application.
In this new case, I had a DataGridView control which was filled using a DataTable and I wanted to programmatically add a row to those displayed in the DataGridView control.
Obtaining the row’s data was simple (calling a web service or by directly querying a database).
The task was then to add the obtained data as a new row of the DataTable used as the source of the control. The problem was again related to the cells containing null values in the new added row.

In fact, if you assign the row’s cells data through a DataRow object you may not have a particular issue. Issues appear when you try to assign an object’s properties values to the row cells.

In this particular case, we had an object with some properties of nullable types: for instance int?  parent_id. The code below generated an error:

DataRow row = table.NewRow()

row["parent_id"] = obj.parent_id;  // an error here when obj.parent_id == null

Some solutions are proposed in several forums. They mainly propose to handle some special events of the DataGridView (like DataError event) and/or play with custom interpretation of DBNull…
The solution I used seems more simple. It is based on the fact that when the row was created (using table.NewRow() method) it contained all required cells… each of which, a priori, filled with something (a sort of ‘null’ thing… we don’t really care about its type). So, we simply may assign cell values only if the data to be assigned is NOT null:

DataRow row = table.NewRow()

if( obj.parent_id != null)

       row["parent_id"] = obj.parent_id;

That seems to work!

Contextual menus… yes! but where is the target node?

TreeView control is a nice and useful control to show many data domains.
One nice and efficient thing of TreeView control is that it allows the developer to handle many aspects of tree nodes by their level in the tree hierarchy. You can for instance choose the icon of items according to their nest level in the tree hierarchy
Among the customizations you can do is to choose a specific contextual menu for each hierarchy level… very cool and simple to do.
When the user right clicks a node in the tree, he or she would see the assigned contextual menu and be able to execute operations in relation to the type of the node.
The thing is, when a menu is clicked, you developer should find out which node was selected when this menu was clicked… Curiously, this is not as simple as we may expect.

I naively thought, a contextual menu object will contain some relevant information about its Target object (in our case: the target Node)… unfortunately this was not true!
So, you simply find yourself with a command to execute (the menu clicked)… but don’t know on which object of the tree should you execute this command!
Few solutions are proposed to solve this problem, and none, of what I read, seemed sustainable.
Here again, we should ‘reinvent the wheel’…

Reinventing the contextual wheel!

The problem seems to be: “Locating the target tree node”. The problem’s definition starts by “Locate”… so let us think “location”.
I first started by trying to locate the mouse cursor at the moment of the click event (using MousePosition which returns the point of the current mouse position in screen coordinates)… but that seemed random, not always related to the node position (and also quite difficult to debugJ).
The next step was to think “location of controls”.
In fact, a contextual menu is a control and as such, it should have a location… hopefully relative to its parent control (which is the TreeView).
Our Click event is received from a contextual menu item (ContextMenuStrip object) which is located into a parent control (the contextual menu box), itself is a child control of the TreeView control containing the node.
The following figure illustrates this disposition 

 

The Owner property of the menu strip contains its parent menu control information. Through this information, we are able to obtain the location of the menu box, and thus, the location  of the first menu strip relative to the TreeView control. With some more simple arithmetic, we can finally locate the right-clicked node (the target node) using the TreeView control GetNodeAt(Point point) method :

 

 

static TreeNode LocateContextMenuTargetNode(

             TreeView            tree_view,

             ToolStripMenuItem   menu_item)

{

       // check entries

       if( tree_view == null || menu_item == null || menu_item.Owner == null)

             return null;

 

       ToolStrip           menu  = menu_item.Owner;

       // top most menu item

       ToolStripMenuItem   first = (ToolStripMenuItem) menu.Items[0];

 

       // obtain the enclosing rectangle of the menu box

       Rectangle           menu_rect   = menu.RectangleToScreen(menu.ClientRectangle);

       // obtain the rectangle relative to the TreeView control

       Rectangle           tv_rect     = tree_view.RectangleToClient(menu_rect);

       // obtain the optimal point that corresponds to the right-clicked node

       Point               point       = newPoint(

                                    first.ContentRectangle.X + tv_rect.X,

                                    first.ContentRectangle.Y + tv_rect.Y);

 

       // finally, get the right-clicked node

       return tree_view.GetNodeAt(point);

 

}

 

 That works fine for contextual menus with few elements and in a ‘normal’ screen resolution.
If the contextual menu contains many items, the first item may be quite far away from the target node!...So, what?
Let us look for a more sustainable way to locate our item… we may again, rethink ‘mouse location’!

In this solution, we will keep track of the current ‘right-clicked node by responding to the MouseDown event of the TreeView.


TreeNode     m_context_menu_target_node; 

void treeView1_MouseDown(object sender, MouseEventArgs e)
{
    // if this is not a right-click: do nothing
    if (e.Button != System.Windows.Forms.MouseButtons.Right)
    {
        m_context_menu_target_node = null;
        return;
    }
 
    Point point = e.Location;

    m_context_menu_target_node = treeView1.GetNodeAt(point);
}

 

Now, when a contextual menu is clicked, we can first see if the target node is not null… execute the command and reset the target node to null (until the next time): 

 
       TreeNode node = m_context_menu_target_node;

       if (node == null)
             return;

       // reset the target node to null
       m_context_menu_target_node = null; 

       // execute the command on the node
      
 

 

Learning from Nature: Towards a 'Nucleotidic' modeling - part I

 

 

 

During several years, I worked on a DNA sequence-analysis software project where I learned about DNA structures and several DNA engineering techniques.

(That is not to be confused with what is commonly called ‘genetic algorithms’ and ‘genetic programming’).

 

Elements and structures used (and manipulated) in molecular biology engineering sphere are fascinating and, above all, source of interesting knowledge. In some way, they define the representation of ‘Life hood’ structures and mechanisms for every living creature (plant, animal, bacteria, virus…)

Molecular biology teaches us that ‘Life’ is based on few nucleotides: A, T, G and C.

Like in music partitions, sequences composed of these few number of nucleotides can give unlimited number of combinations each representing the structure of a specific biological function and, in the end, a specific individual being.

 

Here are some sample (random) fragments of DNA sequences:

 

3’à…GCAATGGTTTCTTACTGTGGAGGACATAAAAATACAGCAAGGGT…à5’

3’à…TTGTGTTGCGAGATGTCGTCGTTAAAGACACTCTTTCTCCCGGAGTCAC…à5’

3’à…CTCTACAGTATAAAGTTCTAGTAAGAGCACAAACTCCTGGACAATTC…à5’

 

Note that DNA sequences are read in a specified direction (noted 3’à5’ in the above sequences).

Nucleotides are considered in complementary (attracted) pairs. A is complementary to T, and G to C.

Each DNA sequence strand has a ‘complementary’ sequence strand where complementary nucleotide pairs are arranged face-to-face in reversed direction to compose part of the well-known helicoidal presentation.

 

Example:

The complementary strand for

3’à…GCAATGGTTTCTTà5’

Is

5’ß…CGTTACCAAAGAAß3’

 

A DNA sequence has its mapped amino acid (protein) sequence. In this mapping, different combinations of three nucleotides (A, T, G or C) compose codons, each mapped to one amino acid (one amino acid may have several codon mappings… see below).

Here are some codon/amino acid mappings:

 

Amino acid

Amino acid Symbol

Codon

Alanine

A

GCA

GCC

GCG

GCT

Arginine

R

AGA

AGG

CGA

CGC

CGG

CGT

Asparagine

N

AAC

AAT

Methionine

M

ATG

 

A sequence may have several “reading frames” in which amino acid codons mapping interpretation may vary. Essentially, to read a sequence, you must first find a starting codon… otherwise; your sequence is the representation of nothing in biological life (real world!)

 

Another interesting aspect is that a specific DNA sequence (with ‘significant’ length) seems to represent one part of a global ‘predefined’ structure… that is, in a way, similar to a known melody in music. If you start to play the first specific notes of, say, a Beatles’ song, everyone can tell the rest of the melody. If your first notes are not specific enough, the result may lead to so many different melodies.

This phenomenon is used in PCR (Polymerase Chain Reaction) in molecular biology engineering to amplify or clone DNA sequences using partial sequences (rigorously selected!).        

 

Useful lessons for software design

Many (if not all J) real world problems seem to follow DNA sequences structure and representations:

§  Basic elements (A, T, G, C)

§  Related each to one another (AT, GC)

§  Composing a global sequence (unique for a specific area)

§  The sequence can be presented differently (DNA /Amino acid)

§  The translation between representations is done through specific mappings (codons / amino acids)

 

PCR technique also seems of great interest to some software areas (OCR recognition for example)

 

I will continue, in future posts, to explore these fascinating structures and propose some applications that mimic and benefit from their behaviors.

 

Throw, but only ‘exceptional’ exceptions!

I find the Try/Catch mechanism fascinating! This is probably due to some events I lived in the (not so far) History! (see below)

The thing is, when I see any of its related keywords: try, catch, finally and, specially, throw… I feel some kind of nervousness or unease!

Unfortunately, for me, more and more source code tries, catches and throws exceptions. It seems sometimes easier to throw an exception while simply an object ‘status’ would be required.

Some history

I remember an intriguing piece of code (2 or 3 C language macros) that was one of the first research I encountered about implementing a dynamic error capturing (now called ‘exception handling’). I kept this code for years (in my ‘code-museum’!) but ended up by losing it through the long journey of OS, compilers and IDEs changes!

Fortunately, I found someone (Francesco Nidito) who still (beautifully) talks about this nearly same macros (you can have a more detailed look here). His article is exactly about the solution that I first saw in the 80s, with some interesting additions (mixed with a good dose of humorJ).

 

If you used C language before, you know the impact (and importance) of ‘preprocessing’. This is the step where the compiler expands the expressions before going further in the compilation process.

For example, if you define a macro:

 

#define SAY_HELLO   int    x;\

                    for( x = 0; x < 10; x++)\

                           printf(“Hello!”);

 

In the preprocessing step, the compiler will replace each SAY_HELLO occurrence by the lines of code above.

 

longjmp And setjmp

Before diving in the historical macros, to better understand their work, we should first have a look at those two (strange) C language functions: longjmp and setjmp (declared in setjmp.h header file):

 

int setjmp(jmp_buf env);

void longjmp(jmp_buf env, int val);

 

The documentation says:

 

The setjmp function saves a stack environment, which you can subsequently restore, using longjmp. When used together, setjmp and longjmp provide a way to execute a non-local goto. They are typically used to pass execution control to error-handling or recovery code in a previously called routine without using the normal calling or return conventions.

A call to setjmp saves the current stack environment in env. A subsequent call to longjmp restores the saved environment and returns control to the point just after the corresponding setjmp call. All variables (except register variables) accessible to the routine receiving control contain the values they had when longjmp was called.

It is not possible to use setjmp to jump from native to managed code.

Note   setjmp and longjmp do not support C++ object semantics. In C++ programs, use the C++ exception-handling mechanism.

The basic Try/Catch macros

Using the magic that can be done by setjmp and longjmp, the following bizarre macros are the basis of a try/catch mechanism:

 

#define TRY            do{ jmp_buf ex_buf__; if( !setjmp(ex_buf__) ){

#define CATCH          } else {

#define ETRY           } }     while(0)

#define THROW          longjmp(ex_buf__, 1)

 

So, now you may write

 

TRY

{

       DoSomething(“with this string”);

}

CATCH

{

       printf(“some error happened!”);

}

ETRY         /* end of try/catch! */

 

At compile-time, this would be expanded to the following code:

 

do{ jmp_buf ex_buf__; if( !setjmp(ex_buf__) ){

{

       DoSomething(“with this string”);

}

} else {

{

       printf(“some error happened!”);

}

} }   while(0)           /* end of try/catch! */

 

 

What does it mean?

Let’s try to read the macros meaning:

TRY, ends with an ETRY. That is do{ xxxx } while(0) (which means: do xxxx only ONCE)

TRY starts by saving the current caller’s stack into a ‘jmp_buf’ variable. If saving the current caller stack succeeds, the next instructions (code block of ‘try’) are executed. Otherwise, the catch block instructions are executed instead.

THROW executes a non-local GOTO (by calling longjmp) which returns execution to the previous caller of the stack saved into the jmp_buf with a return value of 1 (of course, longjmp can be called with a different return value).

 

Anything new?

Of course, our C++, C# and VB Try/Catch mechanism is a little more elaborate than the one exposed here. The foundations remain the same. And, in fact, nothing had fundamentally changed in this area since: any try/catch block executes, at least, this fearful acrobatic setjmp / longjmp.

 

It may be useful to remember this before writing your next try/catch block!

 

Organize your MSDN Help Favorites

If you regularly use MSDN help (Visual Studio Documentation or MSSQL Server Books OnLine (BOL)) you may have noticed that it is not possible to sort or search the list of help favorites.

Migrating these favorites to another machine is almost more painful!

I suffered from these problems for a long time, until I decided to write a tool to help resolving these lacks.

What does the tool do?

HelpFavoriteOrganizer can locate and read your Favorites (xml) file (for Visual Studio or MSSQL documentation) and allow you to sort and search favorite topics. It also locates duplicated topics (i.e. topic having the same help addresses)

You can then save you favorite file, to either a new xml file or overwriting the original XML favorite file.

Another useful feature is to import (merge) an existing xml favorite file into your favorite topics. This can allow an easier roaming life, and can also be used to share your help favorites with someone else.

 

ATTENTION: be careful when deleting items or overwriting files because this tool DOES NOT ask any confirmation. (i.e. use it at your own risk!)

That said (!), you can download it Here: HelpFavoritesOrganizer.zip (34.82 kb)

Some screen captures

Try to locate and load either VStudio help or SQL help favorites

 

 

 

 

.

Sort / Search your topics… items highlighted

Save the list either to a new file or to the original help favorites file.

 

.

Locate / delete duplicated topics (As you can see, I have no more duplicatesJ)

 

.

Import (merge) another favorites xml file