fable
Version:
A service dependency injection, configuration and logging library.
471 lines (402 loc) • 22.2 kB
JavaScript
/**
* Unit tests for Fable Math
*
* @license MIT
*
* @author Steven Velozo <steven@velozo.com>
*/
const libFable = require('../source/Fable.js');
const Chai = require("chai");
const Expect = Chai.expect;
const _ChocoData = require(`./data/chocodata.json`);
suite
(
'Math',
function()
{
suite
(
'Math Operations',
function()
{
test
(
'Exercise Math Tests',
function(fDone)
{
let testFable = new libFable();
Expect(testFable.Math.addPrecise(1, 1)).to.equal('2');
// 3.3333333333333333333333333333333 in the current node.js implementation collapses to 3.3333333333333335
Expect(testFable.Math.addPrecise(1, '3.3333333333333333333333333333333')).to.equal('4.3333333333333333333333333333333');
// Similarly mantissa problems occur with decimals
// So for plain javascript: 0.1 + 0.2 = 0.30000000000000004
Expect(testFable.Math.addPrecise(0.1, 0.2)).to.equal('0.3');
Expect(testFable.Math.subtractPrecise(1, 1)).to.equal('0');
Expect(testFable.Math.multiplyPrecise(1, 1)).to.equal('1');
Expect(testFable.Math.dividePrecise(1, 1)).to.equal('1');
Expect(testFable.Math.percentagePrecise(1, 1)).to.equal('100');
Expect(testFable.Math.percentagePrecise(1, 0)).to.equal('0');
Expect(testFable.Math.percentagePrecise(0, 1)).to.equal('0');
Expect(testFable.Math.percentagePrecise(0, 0)).to.equal('0');
Expect(testFable.Math.percentagePrecise(500, 100)).to.equal('500');
Expect(testFable.Math.percentagePrecise(100, 500)).to.equal('20');
Expect(testFable.Math.powerPrecise(4,4)).to.equal('256');
Expect(testFable.Math.powerPrecise(5,2)).to.equal('25');
Expect(testFable.Math.powerPrecise(50,7)).to.equal('781250000000');
Expect(testFable.Math.sqrtPrecise(4)).to.equal('2');
Expect(testFable.Math.gtPrecise(4, 5)).to.equal(false);
Expect(testFable.Math.gtePrecise(1000, 5)).to.equal(true);
Expect(testFable.Math.gtePrecise('0.00', '0.0')).to.equal(true);
Expect(testFable.Math.gtePrecise('0.00', '0.0000000000000000000000000000000001')).to.equal(false);
Expect(testFable.Math.gtePrecise('0.00', 0.01)).to.equal(false);
Expect(testFable.Math.gtePrecise('0.00', '-0.0000000000000000000000000000000001')).to.equal(true);
Expect(testFable.Math.gtePrecise('0.00', -0.01)).to.equal(true);
Expect(testFable.Math.gtePrecise('0.00000000000000000000000000000000099', '0.000000000000000000000000000000001')).to.equal(false);
Expect(testFable.Math.gtePrecise('0.000000000000000000000000000000001', '0.00000000000000000000000000000000099')).to.equal(true);
Expect(testFable.Math.ltePrecise(1000, 5)).to.equal(false);
Expect(testFable.Math.ltePrecise('0.00', '0.0')).to.equal(true);
Expect(testFable.Math.ltePrecise('0.00', '0.0000000000000000000000000000000001')).to.equal(true);
Expect(testFable.Math.ltePrecise('0.00', 0.01)).to.equal(true);
Expect(testFable.Math.ltePrecise('0.00', '-0.0000000000000000000000000000000001')).to.equal(false);
Expect(testFable.Math.ltePrecise('0.00', -0.01)).to.equal(false);
Expect(testFable.Math.ltePrecise('0.00000000000000000000000000000000099', '0.000000000000000000000000000000001')).to.equal(true);
Expect(testFable.Math.ltePrecise('0.000000000000000000000000000000001', '0.00000000000000000000000000000000099')).to.equal(false);
Expect(testFable.Math.ltPrecise(4, 5)).to.equal(true);
Expect(testFable.Math.floorPrecise(4.939323)).to.equal('4');
Expect(testFable.Math.ceilPrecise(-4.939323)).to.equal('-4');
Expect(testFable.Math.ceilPrecise(4.939323)).to.equal('5');
Expect(testFable.Math.ceilPrecise('BARF')).to.equal('0');
Expect(testFable.Math.ceilPrecise(undefined)).to.equal('0');
Expect(testFable.Math.comparePrecise(4, 5)).to.equal(-1);
Expect(testFable.Math.modPrecise(4.939323, 4)).to.equal('0.939323');
Expect(testFable.Math.absPrecise('-492')).to.equal('492');
return fDone();
}
);
test
(
'Cumulative Summation',
function(fDone)
{
let testFable = new libFable();
let tmpTestValueSet = (
[
{ Item: 'Lettuce', Quantity: 2, Price: "7.99" },
{ Item: 'Tomato', Quantity: 3, Price: "3.99" },
{ Item: 'Onion', Quantity: 1, Price: "1.99" },
{ Item: 'Cucumber', Quantity: 4, Price: "2.99" },
{ Item: 'Carrot', Quantity: 3, Price: "1.99" },
{ Item: 'Radish', Quantity: 2, Price: "1.49" },
{ Item: 'Celery', Quantity: 1, Price: "0.99" },
{ Item: 'Parsley', Quantity: 2, Price: "0.49" }
]);
testFable.Math.cumulativeSummation(tmpTestValueSet, 'Price', 'RunningTotal');
Expect(tmpTestValueSet[0].RunningTotal).to.equal('7.99');
Expect(tmpTestValueSet[1].RunningTotal).to.equal('11.98');
Expect(tmpTestValueSet[2].RunningTotal).to.equal('13.97');
Expect(tmpTestValueSet[3].RunningTotal).to.equal('16.96');
Expect(tmpTestValueSet[4].RunningTotal).to.equal('18.95');
Expect(tmpTestValueSet[5].RunningTotal).to.equal('20.44');
tmpTestValueSet = (
[
{ Item: 'NoCost', Quantity: 2 },
...tmpTestValueSet
]);
testFable.Math.cumulativeSummation(tmpTestValueSet, 'Price', 'RunningTotal');
Expect(tmpTestValueSet[0].RunningTotal).to.equal('0');
Expect(tmpTestValueSet[1].RunningTotal).to.equal('7.99');
Expect(tmpTestValueSet[2].RunningTotal).to.equal('11.98');
Expect(tmpTestValueSet[3].RunningTotal).to.equal('13.97');
Expect(tmpTestValueSet[4].RunningTotal).to.equal('16.96');
Expect(tmpTestValueSet[5].RunningTotal).to.equal('18.95');
Expect(tmpTestValueSet[6].RunningTotal).to.equal('20.44');
return fDone();
}
);
test
(
'Subtractive Summation',
function(fDone)
{
let testFable = new libFable();
let tmpTestValueSet = (
[
{ Item: 'GroceryBag', Volume: '150.00' },
{ Item: 'Lettuce', Volume: '80' },
{ Item: 'Tomato', Volume: '30.17' },
{ Item: 'Onion', Volume: '10.9' },
{ Item: 'Cucumber', Volume: '15.032' }
]);
testFable.Math.subtractingSummation(tmpTestValueSet, 'Volume', 'SpaceLeftInBag');
Expect(tmpTestValueSet[0].SpaceLeftInBag).to.equal('150');
Expect(tmpTestValueSet[1].SpaceLeftInBag).to.equal('70');
Expect(tmpTestValueSet[2].SpaceLeftInBag).to.equal('39.83');
Expect(tmpTestValueSet[3].SpaceLeftInBag).to.equal('28.93');
Expect(tmpTestValueSet[4].SpaceLeftInBag).to.equal('13.898');
return fDone();
}
);
test
(
'Iterative Series Operations',
function(fDone)
{
let testFable = new libFable();
let tmpTestValueSet = (
[
{ Item: 'FirstSplit', Amount: '8' },
{ Item: 'SecondSplit', Amount: '2' },
{ Item: 'ThirdSplit', Amount: '4' },
{ Item: 'FourthSplit', Amount: '2' }
]);
testFable.Math.iterativeSeries(tmpTestValueSet, 'Amount', 'RAMLeft', '1.25', 'divide', '1024', true);
Expect(tmpTestValueSet[0].RAMLeft).to.equal('102.4');
Expect(tmpTestValueSet[1].RAMLeft).to.equal('40.96');
Expect(tmpTestValueSet[2].RAMLeft).to.equal('8.192');
Expect(tmpTestValueSet[3].RAMLeft).to.equal('3.2768');
testFable.Math.iterativeSeries(tmpTestValueSet, 'Amount', 'RAMLeft', '1.0', 'divide', '1024', true);
Expect(tmpTestValueSet[0].RAMLeft).to.equal('128');
Expect(tmpTestValueSet[1].RAMLeft).to.equal('64');
Expect(tmpTestValueSet[2].RAMLeft).to.equal('16');
Expect(tmpTestValueSet[3].RAMLeft).to.equal('8');
testFable.Math.iterativeSeries(tmpTestValueSet, 'Amount', 'RAMLeft', '0.7512', 'mul', '1024', true);
Expect(tmpTestValueSet[0].RAMLeft).to.equal('6153.8304');
Expect(tmpTestValueSet[1].RAMLeft).to.equal('9245.51479296');
Expect(tmpTestValueSet[2].RAMLeft).to.equal('27780.922849886208');
Expect(tmpTestValueSet[3].RAMLeft).to.equal('41738.0584896690388992');
testFable.Math.iterativeSeries(tmpTestValueSet, 'Amount', 'RAMLeft', null, 'sub');
Expect(tmpTestValueSet[0].RAMLeft).to.equal('8');
Expect(tmpTestValueSet[1].RAMLeft).to.equal('6');
Expect(tmpTestValueSet[2].RAMLeft).to.equal('2');
Expect(tmpTestValueSet[3].RAMLeft).to.equal('0');
testFable.Math.iterativeSeries(tmpTestValueSet, 'Amount', 'RAMLeft', undefined, 'sub', 1100);
Expect(tmpTestValueSet[0].RAMLeft).to.equal('1092');
Expect(tmpTestValueSet[1].RAMLeft).to.equal('1090');
Expect(tmpTestValueSet[2].RAMLeft).to.equal('1086');
Expect(tmpTestValueSet[3].RAMLeft).to.equal('1084');
return fDone();
}
);
test
(
'Parse Numbers',
function(fDone)
{
let testFable = new libFable();
Expect(testFable.Math.parsePrecise(1)).to.equal('1');
// 3.3333333333333333333333333333333 in the current node.js implementation collapses to 3.3333333333333335
Expect(testFable.Math.parsePrecise('4.3333333333333333333333333333333')).to.equal('4.3333333333333333333333333333333');
Expect(testFable.Math.parsePrecise(undefined)).to.equal('0.0');
Expect(testFable.Math.parsePrecise('')).to.equal('0.0');
return fDone();
}
);
test
(
'Eulers Number',
function(fDone)
{
let testFable = new libFable();
Expect(testFable.Math.eulerPrecise()).to.equal('2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664');
return fDone();
}
);
test
(
'Histograms by Count',
function(fDone)
{
let testFable = new libFable();
let tmpTestValueSet = (
[
{ City: 'New York', State: 'NY', GDP: 1000000 },
{ City: 'Seattle', State: 'WA', GDP: 500000 },
{ City: 'Portland', State: 'OR', GDP: 250000 },
{ City: 'San Francisco', State: 'CA', GDP: 750000 },
{ City: 'Los Angeles', State: 'CA', GDP: 500000 },
{ City: 'San Diego', State: 'CA', GDP: 250000 },
{ City: 'Atlanta', State: 'GA', GDP: 100000 },
{ City: 'Savannah', State: 'GA', GDP: 50000 },
{ City: 'Athens', State: 'GA', GDP: 25000 }
]);
let tmpHistogramByDistribution = testFable.Math.histogramDistributionByExactValue(tmpTestValueSet, 'State');
Expect(tmpHistogramByDistribution).to.deep.equal({ CA: 3, GA: 3, NY: 1, OR: 1, WA: 1 });
let tmpHistogramByAggregation = testFable.Math.histogramAggregationByExactValue(tmpTestValueSet, 'State', 'GDP');
Expect(tmpHistogramByAggregation).to.deep.equal({ CA: "1500000", GA: "175000", NY: "1000000", OR: "250000", WA: "500000" });
return fDone();
}
);
test
(
'Round Numbers',
function(fDone)
{
let testFable = new libFable();
Expect(testFable.Math.roundPrecise(1.123456789, 2)).to.equal('1.12');
Expect(testFable.Math.roundPrecise(1.123456789, 4)).to.equal('1.1235');
Expect(testFable.Math.roundPrecise(1.123456789, 8)).to.equal('1.12345679');
Expect(testFable.Math.roundPrecise(1.123456789, 10)).to.equal('1.123456789');
Expect(testFable.Math.roundPrecise(1.123456789, 12)).to.equal('1.123456789');
Expect(testFable.Math.roundPrecise(1.123456789, 14)).to.equal('1.123456789');
Expect(testFable.Math.roundPrecise(undefined, 2)).to.equal('0');
try
{
testFable.Math.roundPrecise(null, 2, testFable.Math.roundHalfUp)
}
catch(pError)
{
Expect(pError).to.be.an.instanceof(Error);
Expect(pError.message).to.equal('[big.js] Invalid number');
}
Expect(testFable.Math.roundPrecise('867530999999999.71263219214217312', 15, testFable.Math.roundDown)).to.equal('867530999999999.712632192142173');
Expect(testFable.Math.roundPrecise('867530999999999.71263519214217312', 5, testFable.Math.roundUp)).to.equal('867530999999999.71264');
Expect(testFable.Math.roundPrecise('867530999999999.71263519214217312', 5, testFable.Math.roundHalfUp)).to.equal('867530999999999.71264');
Expect(testFable.Math.roundPrecise('867530999999999.71263519214217312', 5, testFable.Math.roundHalfEven)).to.equal('867530999999999.71264');
Expect(testFable.Math.roundPrecise('867530999999999.71663519214217312', 2, testFable.Math.roundHalfEven)).to.equal('867530999999999.72');
Expect(testFable.Math.roundPrecise('867530999999999.71263519214217312', 4, testFable.Math.roundHalfEven)).to.equal('867530999999999.7126');
return fDone();
}
);
test
(
'Set Math Operations',
function(fDone)
{
let testFable = new libFable();
let testManyfest = testFable.newManyfest();
let tmpChocoSizes = testManyfest.getValueAtAddress(_ChocoData, 'files[].size');
Expect(testFable.Math.maxPrecise(tmpChocoSizes)).to.equal("31625216");
Expect(testFable.Math.minPrecise(tmpChocoSizes)).to.equal("620");
Expect(testFable.Math.sumPrecise(tmpChocoSizes)).to.equal("36431778");
Expect(testFable.Math.countSetElements(tmpChocoSizes)).to.equal(17);
Expect(testFable.Math.meanPrecise(tmpChocoSizes)).to.equal("2143045.76470588235294117647");
Expect(testFable.Math.medianPrecise(tmpChocoSizes)).to.equal("5993");
// Since the file sizes are all different, this is just the whole list.
Expect(testFable.Math.modePrecise(tmpChocoSizes)).to.deep.equal(["620","838","1371","3383","3503","4093","4951","5993","6843","7481","8388","31141","101114","2248166","2378677","31625216","NaN"]);
Expect(testFable.Math.maxPrecise([100, 101, 400, "20", "dog"])).to.equal("400");
Expect(testFable.Math.modePrecise([100, 20, 101, 400, "20", "dog"])).to.deep.equal(["20"]);
Expect(testFable.Math.modePrecise([100, 20, 101, 400, "20", "dog", 101])).to.deep.equal(["20", "101"]);
Expect(testFable.Math.maxPrecise([100, 101, 400, "20", "dog"])).to.equal("400");
Expect(testFable.Math.modePrecise([100, 20, 101, 400, "20", "dog"])).to.deep.equal(["20"]);
Expect(testFable.Math.modePrecise([100, 20, 101, 400, "20", "dog", 101])).to.deep.equal(["20", "101"]);
Expect(testFable.Math.sumPrecise([])).to.equal('0.0');
Expect(testFable.Math.countSetElements([])).to.equal(0);
Expect(testFable.Math.meanPrecise([])).to.equal('0.0');
Expect(testFable.Math.medianPrecise([])).to.equal('0.0');
Expect(testFable.Math.modePrecise([])).to.deep.equal([]);
Expect(testFable.Math.sumPrecise([1,2,3,4,5,6,7,8,9,10])).to.equal('55');
Expect(testFable.Math.countSetElements([1,2,3,4,5,6,7,8,9,10])).to.equal(10);
Expect(testFable.Math.meanPrecise([1,2,3,4,5,6,7,8,9,10])).to.equal('5.5');
Expect(testFable.Math.meanPrecise([0,1,2,3,4,5,6,7,8,9,10])).to.equal('5');
Expect(testFable.Math.medianPrecise([1,2,3,4,5,6,7,8,9,10])).to.equal('5.5');
Expect(testFable.Math.modePrecise([1,2,3,4,5,6,7,8,9,10])).to.deep.equal(['1','2','3','4','5','6','7','8','9','10']);
Expect(testFable.Math.sumPrecise([1,2,3,4,5,6,7,8,9,10,11])).to.equal('66');
Expect(testFable.Math.countSetElements([1,2,3,4,5,6,7,8,9,10,11])).to.equal(11);
Expect(testFable.Math.meanPrecise([1,2,3,4,5,6,7,8,9,10,11])).to.equal('6');
Expect(testFable.Math.medianPrecise([1,2,3,4,5,6,7,8,9,10,11])).to.equal('6');
Expect(testFable.Math.modePrecise([1,2,3,4,5,6,7,8,9,10,11])).to.deep.equal(['1','2','3','4','5','6','7','8','9','10','11']);
return fDone();
}
)
test
(
'Cast To Fixed Numbers',
function(fDone)
{
let testFable = new libFable();
Expect(testFable.Math.toFixedPrecise(1.123456789, 2)).to.equal('1.12');
Expect(testFable.Math.toFixedPrecise(1.123456789, 4)).to.equal('1.1235');
Expect(testFable.Math.toFixedPrecise(1.123456789, 8)).to.equal('1.12345679');
Expect(testFable.Math.toFixedPrecise(1.123456789, 10)).to.equal('1.1234567890');
Expect(testFable.Math.toFixedPrecise(1.123456789, 12)).to.equal('1.123456789000');
Expect(testFable.Math.toFixedPrecise(1.123456789, 14)).to.equal('1.12345678900000');
Expect(testFable.Math.toFixedPrecise(undefined, 2)).to.equal('0.00');
try
{
testFable.Math.toFixedPrecise(null, 2, testFable.Math.roundHalfUp)
}
catch(pError)
{
Expect(pError).to.be.an.instanceof(Error);
Expect(pError.message).to.equal('[big.js] Invalid number');
}
Expect(testFable.Math.toFixedPrecise('867530999999999.71263219214217312', 15, testFable.Math.roundDown)).to.equal('867530999999999.712632192142173');
Expect(testFable.Math.toFixedPrecise('867530999999999.71263519214217312', 5, testFable.Math.roundUp)).to.equal('867530999999999.71264');
Expect(testFable.Math.toFixedPrecise('867530999999999.71263519214217312', 5, testFable.Math.roundHalfUp)).to.equal('867530999999999.71264');
Expect(testFable.Math.toFixedPrecise('867530999999999.71263519214217312', 5, testFable.Math.roundHalfEven)).to.equal('867530999999999.71264');
Expect(testFable.Math.toFixedPrecise('867530999999999.71663519214217312', 2, testFable.Math.roundHalfEven)).to.equal('867530999999999.72');
Expect(testFable.Math.toFixedPrecise('867530999999999.71', 4, testFable.Math.roundHalfEven)).to.equal('867530999999999.7100');
return fDone();
}
);
test
(
'Logarithms',
function(fDone)
{
let testFable = new libFable();
Expect(testFable.Math.logPrecise(0)).to.be.NaN;
Expect(testFable.Math.logPrecise(1.124)).to.equal('0.050766311');
Expect(testFable.Math.logPrecise('1.124')).to.equal('0.050766311');
Expect(testFable.Math.logPrecise('1.4')).to.equal('0.146128036');
Expect(testFable.Math.logPrecise('1.874232')).to.equal('0.272823349');
Expect(testFable.Math.logPrecise('1.9')).to.equal('0.278753601');
Expect(testFable.Math.logPrecise('2.2')).to.equal('0.342422681');
Expect(testFable.Math.logPrecise('3.324')).to.equal('0.521661015');
Expect(testFable.Math.logPrecise('6.32423')).to.equal('0.801007656');
Expect(testFable.Math.logPrecise('7')).to.equal('0.845098040');
Expect(testFable.Math.logPrecise('16')).to.equal('1.204119983');
Expect(testFable.Math.logPrecise('10000')).to.equal('4.000000000');
Expect(testFable.Math.logPrecise('87')).to.equal('1.939519253');
Expect(testFable.Math.logPrecise('100')).to.equal('2.000000000');
Expect(testFable.Math.logPrecise('110')).to.equal('2.041392685');
Expect(testFable.Math.logPrecise('130')).to.equal('2.113943352');
Expect(testFable.Math.logPrecise('400')).to.equal('2.602059991');
Expect(testFable.Math.logPrecise('500')).to.equal('2.698970004');
Expect(testFable.Math.logPrecise('600')).to.equal('2.778151250');
Expect(testFable.Math.logPrecise('900')).to.equal('2.954242509');
Expect(testFable.Math.logPrecise('999')).to.equal('2.999565488');
Expect(testFable.Math.logPrecise('1000')).to.equal('3.000000000');
Expect(testFable.Math.logPrecise('1001')).to.equal('3.000434077');
Expect(testFable.Math.logPrecise('1200')).to.equal('3.079181246');
Expect(testFable.Math.logPrecise('1300')).to.equal('3.113943352');
Expect(testFable.Math.logPrecise('1999')).to.equal('3.300812794');
Expect(testFable.Math.logPrecise('2000')).to.equal('3.301029996');
Expect(testFable.Math.logPrecise('3000')).to.equal('3.477121255');
Expect(testFable.Math.logPrecise('4000')).to.equal('3.602059991');
Expect(testFable.Math.logPrecise('5000')).to.equal('3.698970004');
Expect(testFable.Math.logPrecise('100000')).to.equal('5.000000000');
Expect(testFable.Math.logPrecise('1005000901')).to.equal('9.002166451');
return fDone();
}
);
test
(
'Eulers to an Exponent of N',
function(fDone)
{
let testFable = new libFable();
Expect(testFable.Math.expPrecise('0')).to.equal('1');
Expect(testFable.Math.expPrecise('1.124')).to.equal('3.077138172');
Expect(testFable.Math.expPrecise('1.4')).to.equal('4.055199967');
Expect(testFable.Math.expPrecise('1.874232')).to.equal('6.515813054');
Expect(testFable.Math.expPrecise('1.9')).to.equal('6.685894442');
Expect(testFable.Math.expPrecise('2.2')).to.equal('9.025013499');
Expect(testFable.Math.expPrecise('3.324')).to.equal('27.771213539');
Expect(testFable.Math.expPrecise('6.32423')).to.equal('557.928043628');
Expect(testFable.Math.expPrecise('7')).to.equal('1096.633158427');
Expect(testFable.Math.expPrecise('16')).to.equal('8886110.52050434');
Expect(testFable.Math.expPrecise('87')).to.equal('6.0760302250165910226862305668049228933571005991e+37');
Expect(testFable.Math.expPrecise('100')).to.equal('2.6881171418144006498361355299904430489510323068101727e+43');
Expect(testFable.Math.expPrecise('110')).to.equal('5.92097202763302871775566547178919934033680861763789992544e+47');
Expect(testFable.Math.expPrecise('130')).to.equal('2.87264955081656835249498360594656214322410986618852673463510287128e+56');
Expect(testFable.Math.expPrecise('400')).to.equal('5.22146968976280766823448917819312119928757838636294365087229965314955319234363035967068090474969920921229926737521823711259606341428359454445036263563446386876069161748564476869487107e+173');
Expect(testFable.Math.expPrecise('500')).to.equal('1.4035922178443322635139346187029106729839029888278346358090479055036847329857327659066066346423163346684518112330560812299308307757301544400486805796338124141628072493187592353782193348029633841832360152127536485213047179412609e+217');
Expect(testFable.Math.expPrecise('600')).to.equal('3.77302030092434336419695838674700740088354673638834622388500325660794131835628047153390042345698138347361656320402231485978980283954189824175081056524926295674148482949243810250377530201023308557571234567617672508975937688969808748216814845636042130603884174370820531865e+260');
return fDone();
}
)
}
);
}
);