/// <summary>
        /// Add measure to existing or new transaction line (count canceled trs)
        /// </summary>
        /// <param name="line"></param>
        /// <param name="trsName"></param>
        private void ExtractAddTrsMeasureCSV(string line, string trsName)
        {
            //C;Measure group;Name;Measure type;N;Sum;Min;Max;StdDev;Avg;MinSum;MaxSum;MinMax;MaxMin;MinAvg;MaxAvg;MinCnt;MaxCnt
            //;Transaction;LoketControle_01_inloggen;Trans.(busy) ok[s];4;6,72400000;1,56000000;1,82500000;0,09698711;1,68100000;1,56000000;1,82500000;1,56000000;1,82500000;1,56000000;1,82500000;1,00000000;1,00000000

            if (!_transactionDetails.items.ContainsKey(trsName))
            {
                _transactionDetails.items.Add(trsName, TransactionValue.CreateEmptyValue());
            }

            TransactionValue value = new TransactionValue(_transactionDetails.items[trsName]);

            string[] parts = line.Split(';');

            // failed
            if (line.Contains(TRSFAILEDSUBSTRING))
            {
                value.fail = parts[4];
            }

            // canceled
            if (line.Contains(TRSCANCELEDSUBSTRING))
            {
                value.cancel = parts[4];
            }

            _transactionDetails.items[trsName] = value.ToString();
            //Log.WriteLine("csv data extracted: "+trsName + "=" + value.ToString());
        }
        /// <summary>
        /// Extract the results and put it into transactionDetails: cnt, min, max, avg, stdev
        /// </summary>
        /// <param name="line"></param>
        /// <param name="trsName"></param>
        private void ExtractTrsDetailsCSV(string line, string trsName)
        {
            //C;Measure group;Name;Measure type;N;Sum;Min;Max;StdDev;Avg;MinSum;MaxSum;MinMax;MaxMin;MinAvg;MaxAvg;MinCnt;MaxCnt
            //;Transaction;LoketControle_01_inloggen;Trans.(busy) ok[s];4;6,72400000;1,56000000;1,82500000;0,09698711;1,68100000;1,56000000;1,82500000;1,56000000;1,82500000;1,56000000;1,82500000;1,00000000;1,00000000
            //;Timer;DR_01_OpenDonorregister;Response time[s];1;0,80400000;0,80400000;0,80400000;0,00000000;0,80400000;0,80400000;0,80400000;0,80400000;0,80400000;0,80400000;0,80400000;1,00000000;1,00000000

            string[] parts = line.Split(';');

            // wat nog mist is toevoegen van een lege regel als alles fout gegaan is
            TransactionValue value = new TransactionValue();

            value.cnt   = parts[4];
            value.min   = parts[6].TrimEnd('0');
            value.avg   = parts[9].TrimEnd('0');
            value.max   = parts[7].TrimEnd('0');
            value.stdev = parts[8].TrimEnd('0');

            _transactionDetails.Add(trsName, value.ToString());

            Log.WriteLine(trsName + "=" + value.ToString());
        }
        /// <summary>
        /// Min, max, avg, cnt transactiondata
        /// </summary>
        /// <param name="lines"></param>
        /// <param name="trsNames"></param>
        private TransactionDetails ReadTransactionDetailsFromCSV(string[] lines, string[] trsNames)
        {
            string             trsName;
            TransactionDetails td = new TransactionDetails();

            foreach (string line in lines)
            {
                trsName = Utils.NormalizeTransactionName(line.Split(',')[0]);

                if (trsNames.Contains(trsName))
                {
                    TransactionValue value = ExtractTrsDetailsCSV(line);
                    td.Add(trsName, value.ToString());
                }
            }
            return(td);
        }
        /// <summary>
        /// Extract percentile data from trs summary in bpr/xml
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="trsName"></param>
        private void ExtractAddTrsDetailsXML(string xml, string trsName)
        {
            //string p90 = Regex.Match(xml, @"nr=""90""><Height>(.*?)</Height").Groups[1].Value;
            if (!_transactionDetails.items.ContainsKey(trsName))
            {
                throw new Exception(string.Format("Transaction [{0}] not found in XML/BRP, cannot add percentile data.", trsName));
            }

            TransactionValue value = new TransactionValue(_transactionDetails.items[trsName]);

            // 50, 90 and 99 percentiles are the most used and easily available, the rest can be calculated by interpolation
            value.median = Regex.Match(xml, @"nr=""50""><Height>(.*?)</Height").Groups[1].Value.TrimEnd('0');
            value.p90    = Regex.Match(xml, @"nr=""90""><Height>(.*?)</Height").Groups[1].Value.TrimEnd('0');
            value.p95    = Regex.Match(xml, @"nr=""95""><Height>(.*?)</Height").Groups[1].Value.TrimEnd('0');

            _transactionDetails.items[trsName] = value.ToString();
            //Log.WriteLine(trsName+" brp data extracted, 90p is : "+value.p90);
        }
        /// <summary>
        /// Merge fault data from 'all' transaction data into 'success' transaction data
        /// </summary>
        /// <param name="successTransactionDetails"></param>
        /// <param name="allTransactionDetails"></param>
        private void MergeFaultData(TransactionDetails successTransactionDetails, TransactionDetails allTransactionDetails)
        {
            // iterate over list of all transactions (allTransactionDetails)
            foreach (string trsName in allTransactionDetails.items.GetKeys())
            {
                // if found in successTransactionDetails: some exceptions, so: add only num of faults to existing success story
                if (successTransactionDetails.items.ContainsKey(trsName))
                {
                    // create working object for source- and target data
                    TransactionValue allValue     = new TransactionValue(allTransactionDetails.items[trsName]);
                    TransactionValue successValue = new TransactionValue(successTransactionDetails.items[trsName]);
                    // if all fail (success=0): clear stats
                    if (successValue.cnt == "0")
                    {
                        successValue = new TransactionValue();
                    }

                    // if faults have occured -> calculate fault field
                    if (!successValue.cnt.Equals(allValue.cnt, StringComparison.Ordinal))
                    {
                        successValue.fail = SubtractStrInt(allValue.cnt, successValue.cnt);
                        _transactionDetails.items[trsName] = successValue.ToString(); // replace num of failed
                        Log.WriteLine(string.Format("fault data: {0} faults added to {1}", successValue.fail, trsName));
                    }
                }
                // if not found in successTransactionDetails: 100% exception, so: add empty row with only number of faults
                else
                {
                    TransactionValue newSuccessValue = new TransactionValue();
                    TransactionValue allValue        = new TransactionValue(allTransactionDetails.items[trsName]);
                    // only fill failed field from allvalue (=failed)
                    newSuccessValue.fail = allValue.cnt;
                    _transactionDetails.Add(trsName, newSuccessValue.ToString());
                    Log.WriteLine(string.Format("fault data: no-stats result ({0} faults) for {1}", newSuccessValue.fail, trsName));
                }
            }
        }