Merge branch 'dev' of https://git.verdnatura.es/salix into dev

This commit is contained in:
Juan Ferrer Toribio 2018-02-20 10:00:26 +01:00
commit 1dfafe0d44
25 changed files with 354 additions and 98 deletions

View File

@ -58,7 +58,7 @@
show-field = "description" show-field = "description"
label = "Observation type" label = "Observation type"
order = "description ASC" order = "description ASC"
filter-search="{where: {description: {regexp: 'search'}} }"> filter-search="{where: {description: {regexp: 'search'}}}">
<tpl-item>{{$parent.$parent.item.description}}</tpl-item> <tpl-item>{{$parent.$parent.item.description}}</tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-textfield vn-three label="Description" model="observation.description"></vn-textfield> <vn-textfield vn-three label="Description" model="observation.description"></vn-textfield>
@ -75,8 +75,8 @@
orange orange
icon="add_circle" icon="add_circle"
ng-if = "observation.showAddIcon && observationsTypes.model.length > $ctrl.observations.length" ng-if = "observation.showAddIcon && observationsTypes.model.length > $ctrl.observations.length"
ng-click="$ctrl.addObservation()" ng-click="$ctrl.addObservation()">
></vn-icon> </vn-icon>
</vn-one> </vn-one>
</vn-horizontal> </vn-horizontal>
</vn-one> </vn-one>

View File

@ -3,8 +3,7 @@
label="{{$ctrl.label}}" label="{{$ctrl.label}}"
model="$ctrl.displayValue" model="$ctrl.displayValue"
readonly="$ctrl.readonly" readonly="$ctrl.readonly"
tab-index="-1" tab-index="-1">
>
</vn-textfield> </vn-textfield>
<vn-drop-down vn-auto <vn-drop-down vn-auto
items="$ctrl.items" items="$ctrl.items"
@ -17,6 +16,7 @@
filter-action="$ctrl.findItems(search)" filter-action="$ctrl.findItems(search)"
item-width="$ctrl.width" item-width="$ctrl.width"
multiple="$ctrl.multiple" multiple="$ctrl.multiple"
parent = "$ctrl.element" parent = "$ctrl.element">
><vn-item ng-transclude="tplItem">{{$parent.item[$ctrl.showField]}}</vn-item></vn-drop-down> <vn-item ng-transclude="tplItem">{{$parent.item[$ctrl.showField]}}</vn-item>
</vn-drop-down>
</vn-vertical> </vn-vertical>

View File

@ -1,31 +1,31 @@
<form name="form" ng-submit="$ctrl.submit()"> <form name="form" ng-submit="$ctrl.submit()">
<vn-card> <vn-card>
<vn-vertical pad-large> <vn-vertical pad-large>
<vn-one margin-medium-top> <vn-one margin-medium-top>
<vn-title>Item Barcodes</vn-title> <vn-title>Item Barcodes</vn-title>
<mg-ajax path="/item/api/ItemBarcodes" options="mgIndex as barcodes"></mg-ajax> <mg-ajax path="/item/api/ItemBarcodes" options="mgIndex as barcodes"></mg-ajax>
<vn-horizontal ng-repeat="barcode in $ctrl.barcodes track by $index"> <vn-horizontal ng-repeat="barcode in $ctrl.barcodes track by $index">
<vn-textfield vn-three label="code" model="barcode.code" vn-acl="buyer, replenisher"></vn-textfield> <vn-textfield vn-three label="code" model="barcode.code" vn-acl="buyer, replenisher"></vn-textfield>
<vn-one pad-medium-top> <vn-one pad-medium-top>
<vn-icon <vn-icon
vn-acl="buyer, replenisher" vn-acl="buyer, replenisher"
pointer pointer
medium-grey medium-grey
icon="remove_circle_outline" icon="remove_circle_outline"
ng-click="$ctrl.removeBarcode($index)"> ng-click="$ctrl.removeBarcode($index)">
</vn-icon> </vn-icon>
<vn-icon <vn-icon
vn-acl="buyer, replenisher" vn-acl="buyer, replenisher"
pointer pointer
margin-medium-left margin-medium-left
orange orange
icon="add_circle" icon="add_circle"
ng-if = "barcode.showAddIcon" ng-if = "barcode.showAddIcon"
ng-click="$ctrl.addBarcode()" ng-click="$ctrl.addBarcode()"
></vn-icon> ></vn-icon>
</vn-one> </vn-one>
</vn-horizontal> </vn-horizontal>
</vn-one> </vn-one>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
<vn-button-bar> <vn-button-bar>

View File

@ -1,5 +1,41 @@
<vn-card> <mg-ajax
<vn-vertical pad-large> path="/item/api/ItemBotanicals/{{patch.params.id}}"
<vn-title>Botanical</vn-title> options="vnPatch">
</vn-vertical> </mg-ajax>
</vn-card> <vn-watcher
vn-id="watcher"
data="$ctrl.botanical"
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="watcher.submit()" ng-cloak>
<vn-card>
<vn-vertical pad-large>
<vn-title>Botanical</vn-title>
<vn-horizontal>
<vn-textfield vn-one label="Botanical" model="$ctrl.botanical.botanical"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
initial-data="$ctrl.botanical.genus"
field="$ctrl.botanical.genusFk"
url="/item/api/genera"
show-field="latin_genus_name"
value-field="genus_id"
label="Genus">
</vn-autocomplete>
<vn-autocomplete vn-one
initial-data="$ctrl.botanical.specie"
field="$ctrl.botanical.specieFk"
url="/item/api/species"
show-field="latin_species_name"
value-field="specie_id"
label="Specie">
</vn-autocomplete>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
</vn-button-bar>
</form>

View File

@ -1,5 +1,30 @@
import ngModule from '../module'; import ngModule from '../module';
class ItemBotanical {
constructor($http, $state) {
this.$http = $http;
this.botanical = {
itemFk: $state.params.id
};
}
$onInit() {
let filter = {
where: {
itemFk: this.botanical.itemFk
},
include: [{relation: 'genus'}, {relation: 'specie'}]
};
this.$http.get(`/item/api/ItemBotanicals?filter=${JSON.stringify(filter)}`)
.then(res => {
if (res.data) {
Object.assign(this.botanical, res.data);
}
});
}
}
ItemBotanical.$inject = ['$http', '$state'];
ngModule.component('vnItemBotanical', { ngModule.component('vnItemBotanical', {
template: require('./item-botanical.html') template: require('./item-botanical.html'),
controller: ItemBotanical
}); });

View File

@ -1,9 +1,7 @@
<mg-ajax <mg-ajax
path="/item/api/Items/{{patch.params.id}}" path="/item/api/Items/{{patch.params.id}}"
options="vnPatch" options="vnPatch"
override="{filter: {include: [{relation: 'itemType'}, {relation: 'origin'}, {relation: 'ink'}, {relation: 'producer'}, {relation: 'expence'}]}}" override="{filter: {include: [{relation: 'itemType'}, {relation: 'origin'}, {relation: 'ink'}, {relation: 'producer'}, {relation: 'expence'}]}}">
>
</mg-ajax> </mg-ajax>
<vn-watcher <vn-watcher
vn-id="watcher" vn-id="watcher"
@ -23,8 +21,7 @@
show-field="name" show-field="name"
value-field="id" value-field="id"
field="$ctrl.item.typeFk" field="$ctrl.item.typeFk"
initial-data="$ctrl.item.itemType" initial-data="$ctrl.item.itemType">
>
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
@ -36,14 +33,11 @@
field="$ctrl.item.intrastatFk" field="$ctrl.item.intrastatFk"
order="description ASC" order="description ASC"
filter-search="{where: {description: {regexp: 'search'}} }" filter-search="{where: {description: {regexp: 'search'}} }"
initial-data="$ctrl.item.intrastat" initial-data="$ctrl.item.intrastat">
>
<tpl-item>{{$parent.$parent.item.description}}</tpl-item> <tpl-item>{{$parent.$parent.item.description}}</tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-textfield vn-one label="Relevancy" field="$ctrl.item.relevancy" type="number"></vn-textfield> <vn-textfield vn-one label="Relevancy" field="$ctrl.item.relevancy" type="number"></vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="/item/api/Origins" url="/item/api/Origins"
@ -51,14 +45,14 @@
show-field="name" show-field="name"
value-field="id" value-field="id"
field="$ctrl.item.originFk" field="$ctrl.item.originFk"
initial-data="$ctrl.item.origin" initial-data="$ctrl.item.origin">
></vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="/item/api/Expences" url="/item/api/Expences"
label="Expence" label="Expence"
field="$ctrl.item.expenceFk" field="$ctrl.item.expenceFk"
initial-data="$ctrl.item.expence" initial-data="$ctrl.item.expence">
></vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
@ -66,4 +60,3 @@
<vn-submit label="Save"></vn-submit> <vn-submit label="Save"></vn-submit>
</vn-button-bar> </vn-button-bar>
</form> </form>

View File

@ -145,8 +145,16 @@ export default {
searchItemInput: `${components.vnTextfield}`, searchItemInput: `${components.vnTextfield}`,
searchButton: `${components.vnSearchBar} > vn-icon-button > button` searchButton: `${components.vnSearchBar} > vn-icon-button > button`
}, },
itemBasicData: {
basicDataButton: `${components.vnMenuItem}[ui-sref="item.card.data"]`
},
itemBarcodes: { itemBarcodes: {
barcodeButton: `${components.vnMenuItem}[ui-sref="item.card.itemBarcode"]` barcodeButton: `${components.vnMenuItem}[ui-sref="item.card.itemBarcode"]`,
addBarcodeButton: `${components.vnIcon}[icon="add_circle"]`,
thirdCodeInput: `vn-horizontal:nth-child(5) > ${components.vnTextfield}`,
fourthCodeInput: `vn-horizontal:nth-child(6) > ${components.vnTextfield}`,
submitBarcodesButton: `${components.vnSubmit}`,
firstCodeRemoveButton: `vn-horizontal:nth-child(3) > vn-one > ${components.vnIcon}[icon="remove_circle_outline"]`
} }
}; };

View File

@ -161,4 +161,12 @@ describe('create client path', () => {
expect(result).toEqual(1); expect(result).toEqual(1);
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -206,4 +206,12 @@ describe('Edit basicData path', () => {
expect(result).toEqual('Metropolis newspaper'); expect(result).toEqual('Metropolis newspaper');
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -439,4 +439,12 @@ describe('Edit fiscalData path', () => {
expect(value).toBeTruthy(); expect(value).toBeTruthy();
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -197,4 +197,12 @@ describe('Edit pay method path', () => {
expect(value).toBeFalsy(); expect(value).toBeFalsy();
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -201,4 +201,12 @@ describe('Add address path', () => {
expect(result).toContain('Error'); expect(result).toContain('Error');
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -60,4 +60,12 @@ describe('Add address notes path', () => {
// expect(result).toContain('Some fields are invalid'); // expect(result).toContain('Some fields are invalid');
// }) // })
// }); // });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -88,4 +88,12 @@ describe('Edit web access path', () => {
expect(result).toEqual('Hulk'); expect(result).toEqual('Hulk');
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -68,4 +68,12 @@ describe('Add notes path', () => {
expect(value).toEqual('Meeting with Black Widow 21st 9am'); expect(value).toEqual('Meeting with Black Widow 21st 9am');
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -69,4 +69,12 @@ describe('Add credit path', () => {
expect(value).toContain(999); expect(value).toContain(999);
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -114,4 +114,12 @@ describe('Add greuge path', () => {
expect(value).toContain('Diff'); expect(value).toContain('Diff');
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -50,4 +50,12 @@ describe('mandate path', () => {
expect(value).toContain('CORE'); expect(value).toContain('CORE');
}); });
}); });
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -55,17 +55,55 @@ describe('create item barcodes path', () => {
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
// it(`should click on the search result to access to the item barcodes`, done => { it(`should click on the search result to access to the item barcodes`, done => {
// nightmare nightmare
// .waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time') .waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time')
// .waitToClick(selectors.itemsIndex.searchResult) .waitToClick(selectors.itemsIndex.searchResult)
// .waitToClick(selectors.itemBarcodes.barcodeButton) .waitToClick(selectors.itemBarcodes.barcodeButton)
// .waitForURL('barcode') .waitForURL('barcode')
// .url() .url()
// .then(url => { .then(url => {
// expect(url).toContain('barcode'); expect(url).toContain('barcode');
// done(); done();
// }) })
// .catch(catchErrors(done)); .catch(catchErrors(done));
// }); });
it(`should click create a new code and delete a former one`, done => {
nightmare
.waitToClick(selectors.itemBarcodes.addBarcodeButton)
.type(selectors.itemBarcodes.fourthCodeInput, '5')
.click(selectors.itemBarcodes.firstCodeRemoveButton)
.click(selectors.itemBarcodes.submitBarcodesButton)
.wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => {
expect(result).toContain('Data saved!');
done();
})
.catch(catchErrors(done));
});
it(`should confirm the barcode 5 is created and it is now the third barcode as the first was deleted`, done => {
nightmare
.waitForSnackbarReset()
.click(selectors.itemBasicData.basicDataButton)
.wait(selectors.itemBasicData.nameInput)
.click(selectors.itemBarcodes.barcodeButton)
.wait(200)
.getInputValue(selectors.itemBarcodes.thirdCodeInput)
.then(result => {
expect(result).toEqual('5');
done();
})
.catch(catchErrors(done));
});
describe('closing browser', () => {
it('should close the browser', done => {
nightmare
.end()
.then(done);
});
});
}); });

View File

@ -247,7 +247,6 @@ INSERT INTO `vn2008`.`empresa`(`id`, `abbreviation`, `registro`, `gerente_id`, `
VALUES VALUES
(442, 'WAY', 'Wayne Industries, Inc. operates as a warehouse for steel products.', '2', '1989-11-19', NULL, NULL, '1', '1', '00FF00', 'BruceWayne@verdnatura.es', NULL, '1989-08-11 12:31:22', '10', '1', NULL, '1', '1'); (442, 'WAY', 'Wayne Industries, Inc. operates as a warehouse for steel products.', '2', '1989-11-19', NULL, NULL, '1', '1', '00FF00', 'BruceWayne@verdnatura.es', NULL, '1989-08-11 12:31:22', '10', '1', NULL, '1', '1');
INSERT INTO `vn`.`ticket`(`id`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `clientFk`,`nickname`, `addressFk`) INSERT INTO `vn`.`ticket`(`id`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `clientFk`,`nickname`, `addressFk`)
VALUES VALUES
(1, 1, 1, NULL, CURDATE(), 1, 'Batman', 101), (1, 1, 1, NULL, CURDATE(), 1, 'Batman', 101),
@ -330,7 +329,7 @@ INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`,`workerFk
(1, 'CRI', 'Crisantemo', 2, 15, 5), (1, 'CRI', 'Crisantemo', 2, 15, 5),
(2, 'ITG', 'Anthurium', 1, 30, 5), (2, 'ITG', 'Anthurium', 1, 30, 5),
(3, 'WPN', 'Paniculata', 2, 30, 5); (3, 'WPN', 'Paniculata', 2, 30, 5);
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`) INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`)
VALUES VALUES
('YEL', 'Yellow', 1 , 1), ('YEL', 'Yellow', 1 , 1),
@ -388,12 +387,32 @@ INSERT INTO `vn`.`itemBarcode`(`id`, `itemFk`, `code`)
(3, 1 ,3 ), (3, 1 ,3 ),
(4, 2 ,4 ); (4, 2 ,4 );
INSERT INTO `vn`.`itemPlacement`(`itemFk`, `warehouseFk`, `code`) INSERT INTO `vn`.`itemPlacement`(`id`, `itemFk`, `warehouseFk`, `code`)
VALUES VALUES
(1, 1, 'A1'), (1, 1, 1, 'A1'),
(1, 2, 'A2'), (2, 1, 2, 'A2'),
(1, 3, 'A3'), (3, 1, 3, 'A3'),
(2, 1, 'A4'); (4, 2, 1, 'A4');
INSERT INTO `edi`.`genus`(`genus_id`, `latin_genus_name`, `entry_date`, `expiry_date`, `change_date_time`)
VALUES
( 1, 'Abelia' , CURDATE(), NULL, CURDATE()),
( 2, 'Abies', CURDATE(), NULL, CURDATE()),
( 3, 'Abutilon', CURDATE(), NULL, CURDATE());
INSERT INTO `edi`.`specie`(`specie_id`, `genus_id`, `latin_species_name`, `entry_date`, `expiry_date`, `change_date_time`)
VALUES
( 1, 1, 'grandiflora', CURDATE(), NULL, CURDATE()),
( 2, 2, 'procera', CURDATE(), NULL, CURDATE()),
( 3, 3, 'decurrens', CURDATE(), NULL, CURDATE()),
( 4, 3, 'dealbata', CURDATE(), NULL, CURDATE());
INSERT INTO `vn`.`itemBotanical`(`itemFk`, `botanical`, `genusFk`, `specieFk`)
VALUES
( 1, 'Hedera helix' , 1, 1),
( 2, NULL, 2, 2),
( 3, 'Cycas revoluta', 2, NULL),
( 4, 'Polygonum', NULL, NULL);
INSERT INTO `salix`.`user`(`id`,`username`,`password`,`email`) INSERT INTO `salix`.`user`(`id`,`username`,`password`,`email`)
VALUES VALUES

View File

@ -0,0 +1,16 @@
ALTER TABLE `vn2008`.`Articles_nicho`
DROP FOREIGN KEY `Articles_nichos_fk`;
ALTER TABLE `vn2008`.`Articles_nicho`
CHANGE COLUMN `Id_Article` `Id_Article` INT(11) NOT NULL ,
ADD COLUMN `id` INT NOT NULL AUTO_INCREMENT AFTER `modificationDate`,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`id`);
ALTER TABLE `vn2008`.`Articles_nicho`
ADD CONSTRAINT `Articles_nichos_fk`
FOREIGN KEY (`Id_Article`)
REFERENCES `vn2008`.`Articles` (`Id_Article`)
ON DELETE CASCADE
ON UPDATE CASCADE;

View File

@ -0,0 +1,12 @@
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`itemPlacement` AS
SELECT
`an`.`id` AS `id`,
`an`.`Id_Article` AS `itemFk`,
`an`.`warehouse_id` AS `warehouseFk`,
`an`.`nicho` AS `code`
FROM
`vn2008`.`Articles_nicho` `an`;

View File

@ -1,7 +1,19 @@
const crudItemBarcodes = require('../crudItemBarcodes'); const crudItemBarcodes = require('../crudItemBarcodes');
const catchErrors = require('../../../../../../services/utils/jasmineHelpers').catchErrors; const catchErrors = require('../../../../../../services/utils/jasmineHelpers').catchErrors;
let mysql = require('mysql2');
describe('Item crudItemBarcodes()', () => { describe('Item crudItemBarcodes()', () => {
let connection;
beforeAll(() => {
connection = mysql.createConnection({
multipleStatements: true,
host: 'localhost',
user: 'root',
password: '',
database: 'salix'
});
});
it('should call the destroyAll methodif there are ids in delete Array', done => { it('should call the destroyAll methodif there are ids in delete Array', done => {
let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemBarcodes', 'destroyAll', 'create', 'upsert']); let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemBarcodes', 'destroyAll', 'create', 'upsert']);
@ -48,4 +60,13 @@ describe('Item crudItemBarcodes()', () => {
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should return an error when attempting to save a duplicated barcode', done => {
let callback = (err, res) => {
expect(err.toString()).toBe("Error: Duplicate entry '4' for key 'PRIMARY'");
done();
};
connection.query('INSERT INTO `vn`.`itemBarcode` VALUES (4, 2 ,4 );', callback);
});
}); });

View File

@ -1,28 +1,28 @@
{ {
"name": "ItemBarcode", "name": "ItemBarcode",
"base": "VnModel", "base": "VnModel",
"options": { "options": {
"mysql": { "mysql": {
"table": "itemBarcode", "table": "itemBarcode",
"database": "vn" "database": "vn"
}
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"code": {
"type": "String",
"required": true
} }
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
}, },
"relations": { "code": {
"item": { "type": "String",
"type": "belongsTo", "required": true
"model": "Item",
"foreignKey": "itemFk"
}
} }
},
"relations": {
"item": {
"type": "belongsTo",
"model": "Item",
"foreignKey": "itemFk"
}
} }
}

View File

@ -17,14 +17,14 @@ describe('Client activeSalesPerson', () => {
app.models.Client.activeSalesPerson(filter, callback); app.models.Client.activeSalesPerson(filter, callback);
}); });
it('should call the activeSalesPerson() method with no limit and receive all 3 salesPersons', done => { it('should call the activeSalesPerson() method with no limit and receive all 6 salesPersons', done => {
let filter = { let filter = {
}; };
let callback = (error, result) => { let callback = (error, result) => {
if (error) return catchErrors(done)(error); if (error) return catchErrors(done)(error);
expect(result.length).toEqual(3); expect(result.length).toEqual(6);
done(); done();
}; };