Feeds:
Posts
Comments

RIA.NET + Silverlight 3: Store picture in database and display it in UI controls (DataGrid, DataForm)

We have a table in SQL server with field of “Image” type. We add ADO.NET Entity Data Model by standard way:

Then add table to model. Sql type Image by default is mapping on C# Binary type.

Then Domain Service Class.

And link it with EF Model:

Main rule of web services: to hide service realization (platform and source code of course :) ). RIA.NET code generator creates entity class on client side, where picture stored in field of type – byte[] (simple byte array).

Add DataGrid on from and add DomainDataSource:


               <RiaControls:DomainDataSource x:Name="gamerDataSource"
                LoadMethodName="LoadGamer" LoadSize="20" AutoLoad="True" >
                    <RiaControls:DomainDataSource.DomainContext>
                        <servises:GamerContext/>
                    </RiaControls:DomainDataSource.DomainContext>
                </RiaControls:DomainDataSource> 

In the grid set AutoGenerateColumns=”False”. Add column to grid to display image (add image control into grid field template):


<data:DataGrid.Columns>
                        <data:DataGridTemplateColumn x:Name="PhotoItem" Header="Photo" >
                            <data:DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Image x:Name="PhotoImage" MaxHeight="50" MaxWidth="40" Source ="{Binding Photo, Converter={StaticResource ImageConverter}}"/>
                                </DataTemplate>
                            </data:DataGridTemplateColumn.CellTemplate>
                        </data:DataGridTemplateColumn>
                    </data:DataGrid.Columns>

Direct binding doesn’t work. We need to convert “byte[]” value to “BitmapImage” value (we need write in xaml “Source =”{Binding Photo, Converter={StaticResource ImageConverter}}”/>

There is a simple image converter below:


public class ImageConverter : IValueConverter {
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture) {
BitmapImage bi = new BitmapImage();//create bitmap image
if(value!=null)
//fill bitmap by data from db
bi.SetSource(new MemoryStream((Byte[])value));
return bi;
}

public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();//image is readonly(view only)
}
}

We need to create template field in DataForm (code is the same as in DataGrid):


<dataControls:DataFormTemplateField FieldLabelContent="Photo">
                            <dataControls:DataFormTemplateField.DisplayTemplate>
                                <DataTemplate>
                                    <Image x:Name="PhotoField" Source ="{Binding Photo, Converter={StaticResource ImageConverter}}" MaxWidth="100" MaxHeight="100"/>
                                </DataTemplate>
                            </dataControls:DataFormTemplateField.DisplayTemplate>
                        </dataControls:DataFormTemplateField>

Ok, now we want to open picture and store it on server. It’s very simple:

Add “open picture” button and on Onclick event add this code:

1) Get stream on local file using OpenFileDialog.

2) Read all bytes in array.

3) Assign selected entity Photo field to reader array.


private void LoadPicture_Click(object sender, RoutedEventArgs e) {
var openFileDialog = new OpenFileDialog();
var res = openFileDialog.ShowDialog();
if (res.HasValue &amp;&amp; res.Value) {
Stream stream = openFileDialog.File.OpenRead();
BinaryReader binaryReader = new BinaryReader(stream);
byte[] currentImageInBytes = binaryReader.ReadBytes((int) stream.Length);
//get selected entry from grid
((Gamer) gamerGrid.SelectedItem).Photo = currentImageInBytes;
}
}

And last one, Call DomainDataSource::SubmitChanges to store in Database.

P.S. Waiting for RTM release of RIA.NET. And of course MSDN 2010 ;)

TeamCity 4.5 RELEASED!

TeamCity 4.5 RELEASED!
Read about new features in http://www.jetbrains.com/teamcity/features/newfeatures.html. Migrating from 4.0.2 to 4.5 Now :)

TestComplete integration into TeamCity

We use TestComplete for GUI testing in our work. For faster tests execution we use several PC’s with TestComplete. A unique part of full task list runs on each PC.

But how can we split task for maximum workload of PC? How to combine results without manual work?

It also would be good to include GUI testing in to continuous integration process. As a continuous integration server we use TeamCity. TestComplete can be simply integrated into native AutomatedQA continuous integration server. But this server doesn’t fit our needs. It’s payware and doesn’t support pre-tested commit.

We need to create this:

TeamCity runs GUI tests on all TestComplete clients. NUnit runner will be used as a program which starts distributes tests. All test results will be combining in TestFixture ctor. All TestComplete PC’s has a small web service to handle TeamCity request on test.

Let’s start. On all TestComplete PC we run web service. TeamCity contains project that contains Nunit TestFixture for distributed test run. Web service runs application by client’s parameters. Message sequence on initialization and run test.

As a dispatcher algorithm we use “round robin”. We need simply thread manager for controlling active thread count and providing simple algorithm of synchronization.


using System;
using System.Collections.Generic;
using System.Threading;

namespace ThreadLib {
   ///interface for thread result
   public interface IThreadResult { }

   public delegate T FuncDelegate<T>() where T : IThreadResult;//wrapper for delegate

   public class ThreadControler<T> where T : IThreadResult {
      private class ThreadParam {
         public string Id;
         public FuncDelegate<T> Delegate;
      }
      ///delegates for execution
      private readonly Dictionary<string, FuncDelegate<T>> Delegates = new Dictionary<string, FuncDelegate<T>>();
      ///results
      private readonly Dictionary<string, T> Results = new Dictionary<string, T>();
      private int _MaxParalelThreadCount;
      private static Semaphore Semaphore;

      public ThreadControler(int maxParalelThreadCount) {
         MaxParalelThreadCount = maxParalelThreadCount;
      }

      public T GetResult(string key) {
         if (!Results.ContainsKey(key))
            throw new ArgumentException(string.Format("no result by this key {0}", key));
         return Results[key];
      }

      public void AddDelegate(string key, FuncDelegate<T> @delegate) {
         Delegates.Add(key, @delegate);
      }
      public int MaxParalelThreadCount {
         get { return _MaxParalelThreadCount; }
         set {
            if (value < 1)
               throw new ArgumentException("value<1");
            _MaxParalelThreadCount = value;
         }
      }
///wrapper for delegate
      public void ThreadFunc(object param) {
         var threadParam = (ThreadParam)param;
         var result = threadParam.Delegate();
         lock (Results) {
            Results.Add(threadParam.Id, result);
         }
         Semaphore.Release();
      }
///run all delegate in parallel mode
      public void Run() {
         if (Delegates.Count == 0)
            throw new InvalidOperationException("No Thread for Start");
         if (MaxParalelThreadCount < 1)
            throw new InvalidOperationException("MaxParalelThreadCount<1");

         using(Semaphore = new Semaphore(MaxParalelThreadCount, MaxParalelThreadCount)){
            var threads = new List<Thread>();
            foreach (var key in Delegates.Keys) {
               Semaphore.WaitOne();
               var localKey = key;
               var @delegate = Delegates[localKey];
               var param = new ThreadParam { Delegate = @delegate, Id = localKey };
               var thread = new Thread(ThreadFunc);
               threads.Add(thread);
               thread.Start(param);
            }
            foreach (var thread in threads)
                thread.Join();
         }
      }

   }
}

Web service for running and controlling application (TestComplete for example)

For Service creation I choose WCF. Here simple interface of service:


[ServiceContract]
   public interface ISpreadRunnerService {
      [OperationContract]
      TaskResult TryRunProgramm(string @executable, string @params, int timeout);
   }

For using this server need simple send “exe” name, params for “exe”, and timeout. Also we need to know busy server or not.

Service implementation:


[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class SpreadRunnerService : ISpreadRunnerService
    {
        private readonly object Locker = new object();
//strategy how to run app and how to get app results
        protected IRunProgramStrategy Strategy;
        public virtual TaskResult TryRunProgramm(string executable, string @params, int timeout)
        {
//Lock service!!!
            if (!Monitor.TryEnter(Locker))
            {
                return Strategy.NotRunResult;
            }

            var result= Strategy.Run(executable, @params, timeout);
           Monitor.Exit(Locker);
           return result;
        }
        /// <summary>
        /// only for studio hoster
        /// </summary>
        internal SpreadRunnerService() : this(null) { }
        public SpreadRunnerService(IRunProgramStrategy strategy)
        {
            Strategy = strategy;
        }
    }

SimpleRunStrategy code part. Only run application and return application exit code.


[DataContract]
   public class TaskResult : ITaskResult {
      [DataMember]
      public bool Runned { get; set; }
      [DataMember]
      public bool Hang { get; set; }
      [DataMember]
      public int ProgramResult { get; set; }
      [DataMember]
      public string ExtraData;
   }
public interface IRunProgramStrategy {
      TaskResult Run(string executable, string @params, int timeout);
      TaskResult HangResult { get; }
      TaskResult NotRunResult { get; }
   }
public class RunProgramStrategySimple : IRunProgramStrategy{
/*…*/
public virtual TaskResult Run(string executable, string @params, int timeout) {
         TaskResult result=null;
         try {
            BeforeProcessRun();
            Process p = new Process();
            p.StartInfo.FileName = executable;
            p.StartInfo.Arguments = @params;
            p.Start();
            p.WaitForExit(timeout);
            if (!p.HasExited) {
               p.Kill();
               result= HangResult;
            }
            else
            result= new TaskResult { Hang = false, ProgramResult = p.ExitCode, Runned = true };
         }
         catch (Exception e){
            result= NotRunResult;
            Console.WriteLine(e.Message + " "+executable+
               " "+ @params);
         }
         finally{
            AfterProcessRun(result);
         }
         return result;
      }
/*…*/

Client is also very simple. Here it’s implementation:


public class Task
    {
        public string Id { get; set; }
        public string Executable{get;set;}
        public string Params{get;set;}
        public int Timeout { get; set; }
    }
public class SpreadRunnerClient
    {
//our thread controller
        private ThreadControler<TaskResult> ThreadController = new  ThreadControler<TaskResult>();
//list of service host. May be better use UDDI but…
        internal readonly List<string> Hosts = new List<string>();
//task –that stored in external file
        private List<Task> Tasks = new List<Task>();
public IEnumerable<string> getHosts()
        {
            while(true)
                foreach (string host in Hosts)
                    yield return host;
        }

// create runner delegates for all task and run them in parallel mode
public void RunAllTasks()
        {
            ThreadController.MaxParalelThreadCount = Hosts.Count;
            foreach (var task in Tasks)
            {
                var lockref = task;
                FuncDelegate<TaskResult> func = delegate()
                {
                    while (true)
                    {
                        foreach (string host in getHosts())
                            try
                            {
                               var binding = new WSHttpBinding("WSHttpBinding_ISpreadRunnerService");
                               binding.ReceiveTimeout = TimeSpan.FromMilliseconds(lockref.Timeout*2000);
                               binding.OpenTimeout= TimeSpan.FromMilliseconds(20000);
                               binding.SendTimeout = TimeSpan.FromMilliseconds(lockref.Timeout * 2000);
                               using (var client = new SpreadRunnerServiceClient(binding, new EndpointAddress(host)))
                                {
                                    client.Open();
//try to run application in server
                                    TaskResult result = client.TryRunProgramm(lockref.Executable, lockref.Params, lockref.Timeout);
                                    if (result.Runned)
                                        return result;
                                }
                            }
                            catch { }
                    }
                    throw new ApplicationException();
                };
                ThreadController.AddDelegate(lockref.Id,func);
            }
            ThreadController.Run();
        }

And finally we need to make TestFixture that contain SpreadRunnerClient. In TestFixtureSetUp we must Load All Task from file and give them into SpreadRunnerClient. And call SpreadRunnerClient::RunAllTasks. For handling results we need to write some Test methods, for example:


private static void AssertTests(TaskResult res) {
         bool isnormalresult = res.ProgramResult == 0 || res.ProgramResult == 1;
         Assert.IsTrue(isnormalresult, "result is a " + res.ProgramResult + " |" + res.ExtraData);
         Assert.IsFalse((res.ExtraData.ToLowerInvariant().Contains("exception")), res.ExtraData);
      }
      // ReSharper disable InconsistentNaming
      [Test]
      public void XXXX001() { var res = client.GetResultsById("XXXX001"); AssertTests(res); }

And finally we can run this test in TeamCity:

Resharper  very usefull tool :)  but ...
Sample:

[TestFixture]
   public class Tests {
      [SetUp]
      public void SetUp(){
         Debug.WriteLine("SetUp");
         Assert.IsTrue(false);//can't create some resource
      }
      [TearDown]
      public void TearDown(){
         Debug.WriteLine("TearDown");
      }
      [Test]
      public void Test() { }
   }

Output log Resharper4.1:


Tests.Test : Failed

SetUp

NUnit.Framework.AssertionException:   Expected: True

But was:  False

at NUnit.Framework.Assert.That(Object actual, Constraint constraint, String message, Object[] args)
at NUnit.Framework.Assert.IsTrue(Boolean condition, String message, Object[] args)

at NUnit.Framework.Assert.IsTrue(Boolean condition)at Test.Tests.SetUp() in test.cs: line 14

Output log nunit-gui:

SetUp
VDTest.Tests.Test:
  Expected: True
  But was:  False
at Tests.Tests.SetUp() in tests.cs:line 14
TearDown

teardown must be called in resharper runner. but.......

In test cases I change some rows, add and remove. how to restore it. I try use this way: using PostSharp -AOP framework + TransactionScope objects. on OnEntry in testcase method I create transaction on OnExit from testcase method I remove it:


[Serializable]
   class DoNotMakeChangesInBase : OnMethodBoundaryAspect {
      public override void OnEntry(MethodExecutionEventArgs context) {
         context.MethodExecutionTag = new TransactionScope();
      }
      public override void OnExit(MethodExecutionEventArgs context) {
         using (context.MethodExecutionTag as IDisposable) ;
      }
   }

///using this as:

[DoNotMakeChangesInBase ]

[Test]

public void MyTestCase(){....}

Playing with LinqToObject I create this simple code. Maybe it could be useful for somebody.


public static List<string> SystemFiles(string directory, string pattern, string fileextension) {
         List<string> returnList = new List<string>();
         if(fileextension==")
            fileextension = "*.*"   
         string[] files = Directory.GetFiles(directory, fileextension);
         var outfiles = (from file in files select new { FileName = file, FileLines = File.ReadAllLines(file) }).Select(x => x).Where(x => x.FileLines.Select(line => line).Where(line => Regex.Match(line, pattern).Success).Count() !=0).Select(x => x.FileName);
         foreach (string s in outfiles)
         {
            string str = new FileInfo(s.ToUpper()).Name.ToUpper();
            str = str.Substring(0, str.Length - 4);
            returnList.Add(str);
         }
         return returnList;
      }

I often need to create  database snapshot to compare current snapshot  with old snapshot.  I tried to use standard MSSQL BackUp’s and compare binary files. But it’s very difficult to find row (value) that differing.  I don’t find a free tool for saving database in plane text. And write the following function (this function can be added in nant script :) )


// username is login for local sqlserver instance
//dbname is database name on local sqlserver
//filename is name of out file(name of snapshot)
private static void MakeSQLDump(string username, string dbname, string filename) {
         string gettables =
             @"select table_name
                    FROM  INFORMATION_SCHEMA.TABLES
                    WHERE     (TABLE_TYPE = 'BASE TABLE')
                    order by table_name ";
         string connstr = string.Format("Data Source={0};Initial Catalog={1};Integrated Security=True", username, dbname);
         SqlConnection conn = new SqlConnection(connstr);
         conn.Open();
         SqlCommand gettablescommand = new SqlCommand(gettables, conn);
         SqlDataReader reader = gettablescommand.ExecuteReader();
         List<string> TablesList = new List<string>();
         while (reader.Read()) {
            TablesList.Add(reader.GetString(0));
         }
         reader.Close();
         string getvaluescommandTxt = "select * from {0} order by recnum";
         string GetcolumsNameCommandtxt = "SELECT INFORMATION_SCHEMA.COLUMNS.Column_Name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}'";
         SqlCommand getvaluescommand = new SqlCommand("", conn);
         foreach (string tablename in TablesList) {
            string tmp = "";
            getvaluescommand.CommandText = string.Format(GetcolumsNameCommandtxt, tablename);
            SqlDataReader columsreader = null;
            try {
               columsreader = getvaluescommand.ExecuteReader();
               tmp = string.Format("[{0}]{1}", tablename, Environment.NewLine);
               while (columsreader.Read()) {
                  tmp += string.Format("{0}, ", columsreader.GetString(0));
               }
               tmp.TrimEnd(',');
               tmp += Environment.NewLine;
               WriteStringIntoFile(tmp, filename);
            }
            catch { }
            finally {
               if (columsreader != null)
                  columsreader.Close();
            }

            getvaluescommand.CommandText = string.Format(getvaluescommandTxt, tablename);
            SqlDataReader valreader = null;
            try {

               valreader = getvaluescommand.ExecuteReader();
               tmp = "";
               while (valreader.Read()) {
                  for (int i = 0; i < valreader.FieldCount; i++) {
                     if (valreader.IsDBNull(i)) tmp += "";
                     else tmp += string.Format("\"{0}\"", valreader.GetValue(i));
                     if (i < (valreader.FieldCount - 1)) tmp += ", ";
                  }
                  tmp += Environment.NewLine;
                  WriteStringIntoFile(tmp, filename);
                  tmp = "";
               }
            }
            finally {
               if (valreader != null)
                  valreader.Close();
            }
         }
      }

Getting Nant + nantcontrib. And write following script:


<target name="GetLastVersion">
<!--here get last version into $projectdir-->
</target>
<target name="VssAddFiles">
		<fileset basedir="${projectdir}" id="ServerFiles">
			<include name="**\*.*"/>
			<exclude name="**\*.vspscc"/>
			<exclude name="**\*.vssscc"/>
			<exclude name="**\*.scc"/>
			<exclude name="**\*.vss"/>
			<exclude name="**\*.suo"/>
			<exclude name="**\*.resharper.user"/>
			<exclude name="**\*.resharper"/>
		</fileset>
		<foreach item="File" property="serverFile">
			<in>
				<items refid="ServerFiles"/>
			</in>
			<do>
<property name="localFile"
					value="${string::replace(serverFile, projectdir, tempDir)}" />
<property name="currentFolder"
					value="${path::get-directory-name(serverFile)}" />
<property name="vssPath"
					value="${string::replace(string::replace(currentFolder, projectdir,
						LocalVSSPath), '\', '/')}" />
				<if test=
					"${not file::exists(localFile)
					and not string::contains(localFile, '\obj\')
					and not string::contains(localFile, '\bin\')
					and not string::contains(localFile, '\bin\')
					and not string::contains(localFile, '\build\')
					and not string::contains(localFile, '\MCControls\')
					and not string::contains(localFile, 'ReSharper')}"><!--remove some artefacts-->
					<echo message = "${vssPath}" />
					<vssadd dbpath="\\server\vsstest\srcsafe.ini"
					username="${UserName}" password="${UserPassword}" path="${vssPath}"
					verbose="true">
						<fileset basedir="${currentFolder}">
							<include name="${path::get-file-name(serverFile)}"/>
						</fileset>
					</vssadd>
					<echo message="${serverFile}"/>
				</if>
			</do>
		</foreach>
	</target>
<target name = "ChekinLatestVersion">
        <call target ="GetLastVersion"/>
		<!-- checkout into dummy directory-->
		<vsscheckout
			username="${UserName}"
			password="${UserPassword}"
			localpath="${tempDir}"
			recursive="true"
			writable="false"
			dbpath="${LocalVSSPath}"
			path="${VSSProjectDir}"
		/>
		<!-- checkin from project directory-->
		<vsscheckin
                  username="${UserName}"
				  password="${UserPassword}"
                  localpath="${projectdir}"
                  recursive="true"
                  writable="false"
                  dbpath="${LocalVSSPath}"
				  path="${VSSProjectDir}"
                  comment="NAnt checkin"
        />
		<call target ="VssAddFiles"/>
	</target>

in GetLastVersion you can get from different vcs

CruiseControl.Net is a port of famous CruiseControlContinuous Intagration Server. In our firm we use remote Visual Source Safe Server via VSSConnect. And I write Sourcecontrol Plugin CruiseControl.Net. This plugin should only “Get Latest Version” :) After some googling  I found interface ISourceControl.

Here result plugin code:


using System;
using System.Collections.Generic;
using System.Text;
using ThoughtWorks.CruiseControl.Core;
using ThoughtWorks.CruiseControl.Core.Util;
using Exortech.NetReflector;
using System.Diagnostics;
using System.IO;
using log4net;
using log4net.Core;
namespace ThoughtWorks.CruiseControl.vssprovider {

   [ReflectorType("VSSConnectPlugin")]
   public class VSSConnectPlugin : ISourceControl {
      private readonly ILog logger = LogManager.GetLogger(typeof(MyVssPlugin));

      #region public members
      [ReflectorProperty("args", Required = true)]
      public string Arguments {
         get {
            return _arguments;
         }
         set {
            _arguments = value;
         }
      }

      [ReflectorProperty("vsslog", Required = true)]
      public string VSSLogFile {
         get {
            return _vsslogFileName;
         }
         set {
            _vsslogFileName = value;
         }
      }

      #endregion
      #region private members
      string _arguments = "";
      string _vsslogFileName = "";
      #endregion
      #region ISourceControl Members

      /// Get Modification from vcs. because  vssconnect command line doesn't
      /// support this function, get code
      public Modification[] GetModifications(IIntegrationResult from, IIntegrationResult to) {
         Modification[] modificationArray = null;
         try {
            ProcessStartInfo processStartInfo = new ProcessStartInfo("vssc", Arguments);
            processStartInfo.RedirectStandardOutput = true;
            processStartInfo.UseShellExecute = false;
            Process process = new Process();
            process.StartInfo = processStartInfo;
            process.Start();
            StreamReader streamReader = process.StandardOutput;
            string resultString = streamReader.ReadToEnd();
            return vssoutputparser.Parse(resultString);
         }
         catch {
            if (((IntegrationResult)to).BuildCondition !=
                                      ThoughtWorks.CruiseControl.Remote.BuildCondition.ForceBuild) {
               ((IntegrationResult)to).BuildCondition =
                                      ThoughtWorks.CruiseControl.Remote.BuildCondition.NoBuild;
               ((IntegrationResult)from).BuildCondition =
                                      ThoughtWorks.CruiseControl.Remote.BuildCondition.NoBuild;
            }
            modificationArray = new Modification[0];
         }
         return modificationArray;

      }

      public void GetSource(IIntegrationResult result) {

      }

      public void Initialize(IProject project) {

      }

      public void LabelSourceControl(IIntegrationResult result) {

      }

      public void Purge(IProject project) {

      }

      #endregion
   }
}

using System;
using System.Collections.Generic;
using System.Text;
using ThoughtWorks.CruiseControl.Core;
using ThoughtWorks.CruiseControl.Core.Util;
namespace ThoughtWorks.CruiseControl.vssprovider {
   public class vssoutputparser {
      public static Modification[] Parse(string inStr) {
         List listOfModifiedFile = new List();
         string[] strArray = inStr.Split(new char[] { '\n', '\r' },
StringSplitOptions.RemoveEmptyEntries);
         foreach (string str in strArray) {
            if (str.ToUpper().Contains("Replacing".ToUpper())) {
               string fname = str.ToUpper().Replace("Replacing".ToUpper(), "").Trim();
               listOfModifiedFile.Add(fname);
            }
         }
         Modification[] modificationArray = new Modification[listOfModifiedFile.Count];
         for (int i = 0; i < modificationArray.Length; i++) {
            modificationArray[i] = new Modification();
            int slashPosition = listOfModifiedFile[i].LastIndexOf("\\");
            if (slashPosition != -1) {
               modificationArray[i].FileName =
                              listOfModifiedFile[i].Substring(slashPosition + 1,
                                              listOfModifiedFile[i].Length - slashPosition - 1);
               modificationArray[i].FolderName =
                               listOfModifiedFile[i].Substring(0, slashPosition + 1);
            }
            else {
               modificationArray[i].FileName = listOfModifiedFile[i];
               modificationArray[i].FolderName = "";
            }
            modificationArray[i].ChangeNumber = 0;
            modificationArray[i].Type = "modified";
            modificationArray[i].Version = "0";
         }
         return modificationArray;
      }
   }
}

using in cruisecontrol config file

<sourcecontrol type="VSSConnectPlugin">
	<args>/s:ghttp://XX.XXX.XX.XXX:XXXX/lpath:XXXXXXXXXXXXXXXX
/cmd:getproject /user:"XXXXXXXXXX" /pw:XXXXXXXXX/sspath:$/XXXXXXXXXr</args>
    	<vsslog>XXXXXXXXXXX</vsslog>
</sourcecontrol>