function(stroke, convertFrom, convertTo, timing) {
            return new Promise(function(resolve, reject) {
                console.debug('converting ' + stroke + ' @ ' + timing + ' from ' + convertFrom + ' to ' + convertTo);

                var poolTable = {};
                var strokeTable = {};
                var timingInSeconds = 0;

                //check stroke is a known one
                if (!strokes[stroke]) {
                    reject('ERR: Unrecognised Stroke');
                } else {
                    strokeTable = strokes[stroke];
                    //console.debug('Read stroke table: ', strokeTable);
                }

                //check that time doesn't contain any odd stuff
                if (!timing.match(/[0-9,:,.]/i)) {
                    reject('ERR: Not a Valid Time');
                }
                if ((timing.match(/:/g) || []).length > 1) {
                    reject('ERR: Not a Valid Time');
                }
                if ((timing.match(/\./g) || []).length > 1) {
                    reject('ERR: Not a Valid Time');
                }
                //handle times - convert to seconds, if not already
                try {
                    //check if minutes separator exists
                    if (timing.indexOf(':') > 0) {
                        var _parts = timing.split(':');
                        //assumes no times in hours
                        timingInSeconds = (parseFloat(_parts[0]) * 60) + (parseFloat(_parts[1]));
                    } else {
                        timingInSeconds = parseFloat(timing);
                    }
                } catch (err) {
                    reject('ERR: Incorrect Time Conversion Error: ' + err);
                }

                //check fromPoolLength is a known one
                if (!pools[convertFrom]) {
                    reject('ERR: Unrecognised Pool Length : From');
                } else {
                    poolTable = pools[convertFrom];
                    //console.debug('Read pool table: ', poolTable);
                }
                if (!pools[convertTo]) {
                    reject('ERR: Unrecognised Pool Length : To');
                }

                // start compiling the inputs to the calc
                try {

                    var PoolMeasure = poolTable.poolMeasureCase;
                    console.debug(' - PoolMeasure     :', PoolMeasure);
                    var NumTurnPH = poolTable.numTurnPerHundred;
                    console.debug(' - NumTurnPH       :', NumTurnPH);
                    var Distance = strokeTable.distance;
                    console.debug(' - Distance        :', Distance);
                    var D1 = Distance;
                    console.debug(' - timingInSeconds :', timingInSeconds);
                    //special case for 1500 in short pools
                    if (Distance === 1500 && poolTable.poolMeasureCase === 3) {
                        D1 = 1650;
                    }
                    console.debug(' - D1             :', D1);
                    var NumbTurnFactor = Distance / 100 * (D1 / 100) * (NumTurnPH - 1);
                    console.debug(' - NumbTurnFactor :', NumbTurnFactor);
                    var TurnFactor = strokeTable.TurnFactor;
                    console.debug(' - TurnFactor     :', TurnFactor);

                    // The first Step is to get the value for a 50m form
                    // TimeTo50 = (swtime + Sqr(swtime * swtime + 4 * PoolMeasure * TurnFactor * NumbTurnFactor)) / (2 * PoolMeasure)
                    var T50 = 0;
                    if (convertFrom !== '50m') {
                        T50 = (timingInSeconds +
                            (Math.sqrt(timingInSeconds * timingInSeconds + 4 * PoolMeasure * TurnFactor * NumbTurnFactor))
                        ) / (2 * PoolMeasure);
                    } else {
                        T50 = timingInSeconds;
                    }
                    console.debug(' - T50            :', T50);

                    //The second step – 50m pool length to desired pool length – is expressed as:
                    //T50 * PoolMeasure – TurnVal * (NumTurnPH – 1)
                    // Where:
                    //
                    // T50 = Time in a 50m pool
                    // PoolMeasure = Event distance factor
                    // TurnVal = Time per turn – The time in seconds attributed to execution of a	single turn
                    // NumTurnPH = Number of turns per 100 in the required length pool.
                    // The Time per turn is determined by the relationship:
                    // TurnVal = TurnFactor / T50
                    // Where TurnFactor is provided by the LookUp table

                    var convertTime = 0;

                    var TurnVal = TurnFactor / T50;
                    console.debug(' - TurnVal        :', TurnVal);
                    if (convertTo !== '50m') {
                        convertTime = T50 * 1 - TurnVal * 2;
                    } else {
                        convertTime = T50;
                    }

                    console.debug(' - Result Time    :', convertTime);
                    resolve(convertTime.toFixed(numPlaces).toString());

                } catch (err) {
                    reject('ERR: Conversion Error: ' + err);
                }

            });
        }
function(stroke, convertFrom, convertTo, timing) {
            return new Promise(function(resolve, reject) {
                console.debug('converting ' + stroke + ' @ ' + timing + ' from ' + convertFrom + ' to ' + convertTo);

                var poolTable = {};
                var strokeTable = {};
                var timingInSeconds = 0;

                
                if (!strokes[stroke]) {
                    reject('ERR: Unrecognised Stroke');
                } else {
                    strokeTable = strokes[stroke];
                    
                }

                
                if (!timing.match(/[0-9,:,.]/i)) {
                    reject('ERR: Not a Valid Time');
                }
                if ((timing.match(/:/g) || []).length > 1) {
                    reject('ERR: Not a Valid Time');
                }
                if ((timing.match(/\./g) || []).length > 1) {
                    reject('ERR: Not a Valid Time');
                }
                
                try {
                    
                    if (timing.indexOf(':') > 0) {
                        var _parts = timing.split(':');
                        
                        timingInSeconds = (parseFloat(_parts[0]) * 60) + (parseFloat(_parts[1]));
                    } else {
                        timingInSeconds = parseFloat(timing);
                    }
                } catch (err) {
                    reject('ERR: Incorrect Time Conversion Error: ' + err);
                }

                
                if (!pools[convertFrom]) {
                    reject('ERR: Unrecognised Pool Length : From');
                } else {
                    poolTable = pools[convertFrom];
                    
                }
                if (!pools[convertTo]) {
                    reject('ERR: Unrecognised Pool Length : To');
                }

                
                try {

                    var PoolMeasure = poolTable.poolMeasureCase;
                    console.debug(' - PoolMeasure     :', PoolMeasure);
                    var NumTurnPH = poolTable.numTurnPerHundred;
                    console.debug(' - NumTurnPH       :', NumTurnPH);
                    var Distance = strokeTable.distance;
                    console.debug(' - Distance        :', Distance);
                    var D1 = Distance;
                    console.debug(' - timingInSeconds :', timingInSeconds);
                    
                    if (Distance === 1500 && poolTable.poolMeasureCase === 3) {
                        D1 = 1650;
                    }
                    console.debug(' - D1             :', D1);
                    var NumbTurnFactor = Distance / 100 * (D1 / 100) * (NumTurnPH - 1);
                    console.debug(' - NumbTurnFactor :', NumbTurnFactor);
                    var TurnFactor = strokeTable.TurnFactor;
                    console.debug(' - TurnFactor     :', TurnFactor);

                    
                    
                    var T50 = 0;
                    if (convertFrom !== '50m') {
                        T50 = (timingInSeconds +
                            (Math.sqrt(timingInSeconds * timingInSeconds + 4 * PoolMeasure * TurnFactor * NumbTurnFactor))
                        ) / (2 * PoolMeasure);
                    } else {
                        T50 = timingInSeconds;
                    }
                    console.debug(' - T50            :', T50);

                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    

                    var convertTime = 0;

                    var TurnVal = TurnFactor / T50;
                    console.debug(' - TurnVal        :', TurnVal);
                    if (convertTo !== '50m') {
                        convertTime = T50 * 1 - TurnVal * 2;
                    } else {
                        convertTime = T50;
                    }

                    console.debug(' - Result Time    :', convertTime);
                    resolve(convertTime.toFixed(numPlaces).toString());

                } catch (err) {
                    reject('ERR: Conversion Error: ' + err);
                }

            });
        }
function ( stroke , convertFrom , convertTo , timing ) { return new Promise ( function ( resolve , reject ) { console . debug ( 'converting ' + stroke + ' @ ' + timing + ' from ' + convertFrom + ' to ' + convertTo ) ; var poolTable = { } ; var strokeTable = { } ; var timingInSeconds = 0 ; //check stroke is a known one if ( ! strokes [ stroke ] ) { reject ( 'ERR: Unrecognised Stroke' ) ; } else { strokeTable = strokes [ stroke ] ; //console.debug('Read stroke table: ', strokeTable); } //check that time doesn't contain any odd stuff if ( ! timing . match ( / [0-9,:,.] / i ) ) { reject ( 'ERR: Not a Valid Time' ) ; } if ( ( timing . match ( / : / g ) || [ ] ) . length > 1 ) { reject ( 'ERR: Not a Valid Time' ) ; } if ( ( timing . match ( / \. / g ) || [ ] ) . length > 1 ) { reject ( 'ERR: Not a Valid Time' ) ; } //handle times - convert to seconds, if not already try { //check if minutes separator exists if ( timing . indexOf ( ':' ) > 0 ) { var _parts = timing . split ( ':' ) ; //assumes no times in hours timingInSeconds = ( parseFloat ( _parts [ 0 ] ) * 60 ) + ( parseFloat ( _parts [ 1 ] ) ) ; } else { timingInSeconds = parseFloat ( timing ) ; } } catch ( err ) { reject ( 'ERR: Incorrect Time Conversion Error: ' + err ) ; } //check fromPoolLength is a known one if ( ! pools [ convertFrom ] ) { reject ( 'ERR: Unrecognised Pool Length : From' ) ; } else { poolTable = pools [ convertFrom ] ; //console.debug('Read pool table: ', poolTable); } if ( ! pools [ convertTo ] ) { reject ( 'ERR: Unrecognised Pool Length : To' ) ; } // start compiling the inputs to the calc try { var PoolMeasure = poolTable . poolMeasureCase ; console . debug ( ' - PoolMeasure     :' , PoolMeasure ) ; var NumTurnPH = poolTable . numTurnPerHundred ; console . debug ( ' - NumTurnPH       :' , NumTurnPH ) ; var Distance = strokeTable . distance ; console . debug ( ' - Distance        :' , Distance ) ; var D1 = Distance ; console . debug ( ' - timingInSeconds :' , timingInSeconds ) ; //special case for 1500 in short pools if ( Distance === 1500 && poolTable . poolMeasureCase === 3 ) { D1 = 1650 ; } console . debug ( ' - D1             :' , D1 ) ; var NumbTurnFactor = Distance / 100 * ( D1 / 100 ) * ( NumTurnPH - 1 ) ; console . debug ( ' - NumbTurnFactor :' , NumbTurnFactor ) ; var TurnFactor = strokeTable . TurnFactor ; console . debug ( ' - TurnFactor     :' , TurnFactor ) ; // The first Step is to get the value for a 50m form // TimeTo50 = (swtime + Sqr(swtime * swtime + 4 * PoolMeasure * TurnFactor * NumbTurnFactor)) / (2 * PoolMeasure) var T50 = 0 ; if ( convertFrom !== '50m' ) { T50 = ( timingInSeconds + ( Math . sqrt ( timingInSeconds * timingInSeconds + 4 * PoolMeasure * TurnFactor * NumbTurnFactor ) ) ) / ( 2 * PoolMeasure ) ; } else { T50 = timingInSeconds ; } console . debug ( ' - T50            :' , T50 ) ; //The second step – 50m pool length to desired pool length – is expressed as: //T50 * PoolMeasure – TurnVal * (NumTurnPH – 1) // Where: // // T50 = Time in a 50m pool // PoolMeasure = Event distance factor // TurnVal = Time per turn – The time in seconds attributed to execution of a	single turn // NumTurnPH = Number of turns per 100 in the required length pool. // The Time per turn is determined by the relationship: // TurnVal = TurnFactor / T50 // Where TurnFactor is provided by the LookUp table var convertTime = 0 ; var TurnVal = TurnFactor / T50 ; console . debug ( ' - TurnVal        :' , TurnVal ) ; if ( convertTo !== '50m' ) { convertTime = T50 * 1 - TurnVal * 2 ; } else { convertTime = T50 ; } console . debug ( ' - Result Time    :' , convertTime ) ; resolve ( convertTime . toFixed ( numPlaces ) . toString ( ) ) ; } catch ( err ) { reject ( 'ERR: Conversion Error: ' + err ) ; } } ) ; }
getTimePromise function to convert Swim times based on ASA table
getTime(convertFrom, convertTo, stroke, timing)

based on formula documented
https://www.swimmingresults.org/downloads/equivalent-time-share/algorithm.php

inputs
@param {string} stroke is stroke as per the list.
@param {string} covertFrom is poolLength.
@param {string} convertTo is poolLength.
@param {time}   timing is time to convert from.

returns
@return {promise} returns a promise to supply the time
@return {time}  time per target
getTimePromise function to convert Swim times based on ASA table getTime ( convertFrom convertTo stroke timing )