@ -2,6 +2,7 @@
const setup = require ( '../../../controller/coarse_reverse' ) ;
const setup = require ( '../../../controller/coarse_reverse' ) ;
const proxyquire = require ( 'proxyquire' ) . noCallThru ( ) ;
const proxyquire = require ( 'proxyquire' ) . noCallThru ( ) ;
const _ = require ( 'lodash' ) ;
module . exports . tests = { } ;
module . exports . tests = { } ;
@ -15,12 +16,13 @@ module.exports.tests.interface = (test, common) => {
module . exports . tests . early _exit _conditions = ( test , common ) => {
module . exports . tests . early _exit _conditions = ( test , common ) => {
test ( 'should_execute returning false should not call service' , ( t ) => {
test ( 'should_execute returning false should not call service' , ( t ) => {
t . plan ( 2 ) ;
const service = ( ) => {
const service = ( ) => {
throw Error ( 'service should not have been called' ) ;
throw Error ( 'service should not have been called' ) ;
} ;
} ;
const should _execute = ( ) => { return false ; } ;
const controller = setup ( service , _ . constant ( false ) ) ;
const controller = setup ( service , should _execute ) ;
const req = {
const req = {
clean : {
clean : {
@ -30,14 +32,12 @@ module.exports.tests.early_exit_conditions = (test, common) => {
} ;
} ;
// verify that next was called
// verify that next was called
let next _was _called = false ;
const next = ( ) => {
const next = ( ) => {
next _was _called = true ;
t . pass ( 'next() was called' ) ;
} ;
} ;
// passing res=undefined verifies that it wasn't interacted with
// passing res=undefined verifies that it wasn't interacted with
t . doesNotThrow ( controller . bind ( null , req , undefined , next ) ) ;
t . doesNotThrow ( controller . bind ( null , req , undefined , next ) ) ;
t . ok ( next _was _called ) ;
t . end ( ) ;
t . end ( ) ;
} ) ;
} ) ;
@ -46,44 +46,108 @@ module.exports.tests.early_exit_conditions = (test, common) => {
module . exports . tests . error _conditions = ( test , common ) => {
module . exports . tests . error _conditions = ( test , common ) => {
test ( 'service error should log and call next' , ( t ) => {
test ( 'service error should log and call next' , ( t ) => {
const service = ( point , do _not _track , callback ) => {
t . plan ( 3 ) ;
t . equals ( do _not _track , 'do_not_track value' ) ;
const service = ( req , callback ) => {
t . deepEquals ( req , { clean : { layers : [ 'locality' ] } } ) ;
callback ( 'this is an error' ) ;
callback ( 'this is an error' ) ;
} ;
} ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const should _execute = ( ) => { return true ; } ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger ,
'pelias-logger' : logger
'../helper/logging' : {
} ) ( service , _ . constant ( true ) ) ;
isDNT : ( ) => {
return 'do_not_track value' ;
}
}
} ) ( service , should _execute ) ;
const req = {
const req = {
clean : {
clean : {
layers : [ 'locality' ] ,
layers : [ 'locality' ]
point : {
lat : 12.121212 ,
lon : 21.212121
}
}
}
} ;
} ;
// verify that next was called
// verify that next was called
let next _was _called = false ;
const next = ( ) => {
const next = ( ) => {
next _was _called = true ;
t . pass ( 'next() was called' ) ;
} ;
} ;
// passing res=undefined verifies that it wasn't interacted with
// passing res=undefined verifies that it wasn't interacted with
controller ( req , undefined , next ) ;
controller ( req , undefined , next ) ;
t . ok ( logger . isErrorMessage ( 'this is an error' ) ) ;
t . ok ( logger . isErrorMessage ( 'this is an error' ) ) ;
t . ok ( next _was _called ) ;
t . end ( ) ;
} ) ;
} ;
module . exports . tests . boundary _circle _radius _warnings = ( test , common ) => {
test ( 'defined clean[boundary.circle.radius] should add a warning' , ( t ) => {
const service = ( req , callback ) => {
callback ( undefined , { } ) ;
} ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger
} ) ( service , _ . constant ( true ) ) ;
const req = {
warnings : [ ] ,
clean : {
'boundary.circle.radius' : 17
}
} ;
const res = { } ;
const next = ( ) => { } ;
controller ( req , res , next ) ;
const expected = {
meta : { } ,
data : [ ]
} ;
t . deepEquals ( req . warnings , [ 'boundary.circle.radius is not applicable for coarse reverse' ] ) ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . end ( ) ;
} ) ;
test ( 'defined clean[boundary.circle.radius] should add a warning' , ( t ) => {
const service = ( req , callback ) => {
callback ( undefined , { } ) ;
} ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger
} ) ( service , _ . constant ( true ) ) ;
const req = {
warnings : [ ] ,
clean : { }
} ;
const res = { } ;
// verify that next was called
const next = ( ) => { } ;
controller ( req , res , next ) ;
const expected = {
meta : { } ,
data : [ ]
} ;
t . deepEquals ( req . warnings , [ ] ) ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . end ( ) ;
t . end ( ) ;
} ) ;
} ) ;
@ -92,8 +156,11 @@ module.exports.tests.error_conditions = (test, common) => {
module . exports . tests . success _conditions = ( test , common ) => {
module . exports . tests . success _conditions = ( test , common ) => {
test ( 'service returning results should use first entry for each layer' , ( t ) => {
test ( 'service returning results should use first entry for each layer' , ( t ) => {
const service = ( point , do _not _track , callback ) => {
t . plan ( 4 ) ;
t . equals ( do _not _track , 'do_not_track value' ) ;
const service = ( req , callback ) => {
t . deepEquals ( req , { clean : { layers : [ 'neighbourhood' ] } } ) ;
const results = {
const results = {
neighbourhood : [
neighbourhood : [
{
{
@ -151,32 +218,21 @@ module.exports.tests.success_conditions = (test, common) => {
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const should _execute = ( ) => { return true ; } ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger ,
'pelias-logger' : logger
'../helper/logging' : {
} ) ( service , _ . constant ( true ) ) ;
isDNT : ( ) => {
return 'do_not_track value' ;
}
}
} ) ( service , should _execute ) ;
const req = {
const req = {
clean : {
clean : {
layers : [ 'neighbourhood' ] ,
layers : [ 'neighbourhood' ]
point : {
lat : 12.121212 ,
lon : 21.212121
}
}
}
} ;
} ;
const res = { } ;
const res = { } ;
// verify that next was called
// verify that next was called
let next _was _called = false ;
const next = ( ) => {
const next = ( ) => {
next _was _called = true ;
t . pass ( 'next() was called' ) ;
} ;
} ;
controller ( req , res , next ) ;
controller ( req , res , next ) ;
@ -228,7 +284,6 @@ module.exports.tests.success_conditions = (test, common) => {
country _id : [ '100' ] ,
country _id : [ '100' ] ,
country _a : [ 'xyz' ]
country _a : [ 'xyz' ]
} ,
} ,
alpha3 : 'XYZ' ,
center _point : {
center _point : {
lat : 12.121212 ,
lat : 12.121212 ,
lon : 21.212121
lon : 21.212121
@ -239,22 +294,22 @@ module.exports.tests.success_conditions = (test, common) => {
} ;
} ;
t . deepEquals ( res , expected ) ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . ok ( next _was _called ) ;
t . end ( ) ;
t . end ( ) ;
} ) ;
} ) ;
test ( 'layers missing from results should be ignored' , ( t ) => {
test ( 'layers missing from results should be ignored' , ( t ) => {
const service = ( point , do _not _track , callback ) => {
t . plan ( 4 ) ;
t . equals ( do _not _track , 'do_not_track value' ) ;
const service = ( req , callback ) => {
t . deepEquals ( req , { clean : { layers : [ 'neighbourhood' ] } } ) ;
const results = {
const results = {
neighbourhood : [
neighbourhood : [
{
{
id : 10 ,
id : 10 ,
name : 'neighbourhood name' ,
name : 'neighbourhood name' ,
abbr : 'neighbourhood abbr' ,
centroid : {
centroid : {
lat : 12.121212 ,
lat : 12.121212 ,
lon : 21.212121
lon : 21.212121
@ -269,32 +324,21 @@ module.exports.tests.success_conditions = (test, common) => {
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const should _execute = ( ) => { return true ; } ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger ,
'pelias-logger' : logger
'../helper/logging' : {
} ) ( service , _ . constant ( true ) ) ;
isDNT : ( ) => {
return 'do_not_track value' ;
}
}
} ) ( service , should _execute ) ;
const req = {
const req = {
clean : {
clean : {
layers : [ 'neighbourhood' ] ,
layers : [ 'neighbourhood' ]
point : {
lat : 12.121212 ,
lon : 21.212121
}
}
}
} ;
} ;
const res = { } ;
const res = { } ;
// verify that next was called
// verify that next was called
let next _was _called = false ;
const next = ( ) => {
const next = ( ) => {
next _was _called = true ;
t . pass ( 'next() was called' ) ;
} ;
} ;
controller ( req , res , next ) ;
controller ( req , res , next ) ;
@ -317,7 +361,7 @@ module.exports.tests.success_conditions = (test, common) => {
parent : {
parent : {
neighbourhood : [ 'neighbourhood name' ] ,
neighbourhood : [ 'neighbourhood name' ] ,
neighbourhood _id : [ '10' ] ,
neighbourhood _id : [ '10' ] ,
neighbourhood _a : [ 'neighbourhood abbr' ]
neighbourhood _a : [ null ]
} ,
} ,
center _point : {
center _point : {
lat : 12.121212 ,
lat : 12.121212 ,
@ -329,16 +373,17 @@ module.exports.tests.success_conditions = (test, common) => {
} ;
} ;
t . deepEquals ( res , expected ) ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . ok ( next _was _called ) ;
t . end ( ) ;
t . end ( ) ;
} ) ;
} ) ;
test ( 'most granular layer missing centroid should not set' , ( t ) => {
test ( 'most granular layer missing centroid should not set' , ( t ) => {
const service = ( point , do _not _track , callback ) => {
t . plan ( 4 ) ;
t . equals ( do _not _track , 'do_not_track value' ) ;
const service = ( req , callback ) => {
t . deepEquals ( req , { clean : { layers : [ 'neighbourhood' ] } } ) ;
const results = {
const results = {
neighbourhood : [
neighbourhood : [
{
{
@ -355,32 +400,21 @@ module.exports.tests.success_conditions = (test, common) => {
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const should _execute = ( ) => { return true ; } ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger ,
'pelias-logger' : logger
'../helper/logging' : {
} ) ( service , _ . constant ( true ) ) ;
isDNT : ( ) => {
return 'do_not_track value' ;
}
}
} ) ( service , should _execute ) ;
const req = {
const req = {
clean : {
clean : {
layers : [ 'neighbourhood' ] ,
layers : [ 'neighbourhood' ]
point : {
lat : 12.121212 ,
lon : 21.212121
}
}
}
} ;
} ;
const res = { } ;
const res = { } ;
// verify that next was called
// verify that next was called
let next _was _called = false ;
const next = ( ) => {
const next = ( ) => {
next _was _called = true ;
t . pass ( 'next() was called' ) ;
} ;
} ;
controller ( req , res , next ) ;
controller ( req , res , next ) ;
@ -411,16 +445,17 @@ module.exports.tests.success_conditions = (test, common) => {
} ;
} ;
t . deepEquals ( res , expected ) ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . ok ( next _was _called ) ;
t . end ( ) ;
t . end ( ) ;
} ) ;
} ) ;
test ( 'most granular layer missing bounding_box should not set' , ( t ) => {
test ( 'most granular layer missing bounding_box should not set' , ( t ) => {
const service = ( point , do _not _track , callback ) => {
t . plan ( 4 ) ;
t . equals ( do _not _track , 'do_not_track value' ) ;
const service = ( req , callback ) => {
t . deepEquals ( req , { clean : { layers : [ 'neighbourhood' ] } } ) ;
const results = {
const results = {
neighbourhood : [
neighbourhood : [
{
{
@ -440,19 +475,91 @@ module.exports.tests.success_conditions = (test, common) => {
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const should _execute = ( ) => { return true ; } ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger ,
'pelias-logger' : logger
'../helper/logging' : {
} ) ( service , _ . constant ( true ) ) ;
isDNT : ( ) => {
return 'do_not_track value' ;
const req = {
clean : {
layers : [ 'neighbourhood' ]
}
} ;
const res = { } ;
// verify that next was called
const next = ( ) => {
t . pass ( 'next() was called' ) ;
} ;
controller ( req , res , next ) ;
const expected = {
meta : { } ,
data : [
{
_id : '10' ,
_type : 'neighbourhood' ,
layer : 'neighbourhood' ,
source : 'whosonfirst' ,
source _id : '10' ,
name : {
'default' : 'neighbourhood name'
} ,
phrase : {
'default' : 'neighbourhood name'
} ,
parent : {
neighbourhood : [ 'neighbourhood name' ] ,
neighbourhood _id : [ '10' ] ,
neighbourhood _a : [ 'neighbourhood abbr' ]
} ,
center _point : {
lat : 12.121212 ,
lon : 21.212121
}
}
}
]
} ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . end ( ) ;
} ) ;
test ( 'no requested layers should use everything' , ( t ) => {
// this test is used to test coarse reverse fallback for when non-coarse reverse
// was requested but no non-coarse results were found
// by plan'ing the number of tests, we can verify that next() was called w/o
// additional bookkeeping
t . plan ( 4 ) ;
const service = ( req , callback ) => {
const results = {
neighbourhood : [
{
id : 10 ,
name : 'neighbourhood name' ,
abbr : 'neighbourhood abbr'
}
}
} ) ( service , should _execute ) ;
]
} ;
callback ( undefined , results ) ;
} ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger
} ) ( service , _ . constant ( true ) ) ;
const req = {
const req = {
clean : {
clean : {
layers : [ 'neighbourhood' ] ,
layers : [ ] ,
point : {
point : {
lat : 12.121212 ,
lat : 12.121212 ,
lon : 21.212121
lon : 21.212121
@ -463,9 +570,8 @@ module.exports.tests.success_conditions = (test, common) => {
const res = { } ;
const res = { } ;
// verify that next was called
// verify that next was called
let next _was _called = false ;
const next = ( ) => {
const next = ( ) => {
next _was _called = true ;
t . pass ( 'next() should have been called' ) ;
} ;
} ;
controller ( req , res , next ) ;
controller ( req , res , next ) ;
@ -489,19 +595,183 @@ module.exports.tests.success_conditions = (test, common) => {
neighbourhood : [ 'neighbourhood name' ] ,
neighbourhood : [ 'neighbourhood name' ] ,
neighbourhood _id : [ '10' ] ,
neighbourhood _id : [ '10' ] ,
neighbourhood _a : [ 'neighbourhood abbr' ]
neighbourhood _a : [ 'neighbourhood abbr' ]
} ,
}
center _point : {
}
]
} ;
t . deepEquals ( req . clean . layers , [ ] , 'req.clean.layers should be unmodified' ) ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . end ( ) ;
} ) ;
test ( 'layers specifying only venue, address, or street should not exclude coarse results' , ( t ) => {
// this test is used to test coarse reverse fallback for when non-coarse reverse
// was requested but no non-coarse results were found
const non _coarse _layers = [ 'venue' , 'address' , 'street' ] ;
const tests _per _non _coarse _layer = 4 ;
// by plan'ing the number of tests, we can verify that next() was called w/o
// additional bookkeeping
t . plan ( non _coarse _layers . length * tests _per _non _coarse _layer ) ;
non _coarse _layers . forEach ( ( non _coarse _layer ) => {
const service = ( req , callback ) => {
const results = {
neighbourhood : [
{
id : 10 ,
name : 'neighbourhood name' ,
abbr : 'neighbourhood abbr'
}
]
} ;
callback ( undefined , results ) ;
} ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger
} ) ( service , _ . constant ( true ) ) ;
const req = {
clean : {
layers : [ non _coarse _layer ] ,
point : {
lat : 12.121212 ,
lat : 12.121212 ,
lon : 21.212121
lon : 21.212121
}
}
}
}
} ;
const res = { } ;
// verify that next was called
const next = ( ) => {
t . pass ( 'next() should have been called' ) ;
} ;
controller ( req , res , next ) ;
const expected = {
meta : { } ,
data : [
{
_id : '10' ,
_type : 'neighbourhood' ,
layer : 'neighbourhood' ,
source : 'whosonfirst' ,
source _id : '10' ,
name : {
'default' : 'neighbourhood name'
} ,
phrase : {
'default' : 'neighbourhood name'
} ,
parent : {
neighbourhood : [ 'neighbourhood name' ] ,
neighbourhood _id : [ '10' ] ,
neighbourhood _a : [ 'neighbourhood abbr' ]
}
}
]
]
} ;
} ;
t . deepEquals ( req . clean . layers , [ non _coarse _layer ] , 'req.clean.layers should be unmodified' ) ;
t . deepEquals ( res , expected ) ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
} ) ;
t . end ( ) ;
} ) ;
test ( 'layers specifying venue, address, or street AND coarse layer should not exclude coarse results' , ( t ) => {
// this test is used to test coarse reverse fallback for when non-coarse reverse
// was requested but no non-coarse results were found
const non _coarse _layers = [ 'venue' , 'address' , 'street' ] ;
const tests _per _non _coarse _layer = 4 ;
// by plan'ing the number of tests, we can verify that next() was called w/o
// additional bookkeeping
t . plan ( non _coarse _layers . length * tests _per _non _coarse _layer ) ;
non _coarse _layers . forEach ( ( non _coarse _layer ) => {
const service = ( req , callback ) => {
const results = {
neighbourhood : [
{
id : 10 ,
name : 'neighbourhood name' ,
abbr : 'neighbourhood abbr'
}
]
} ;
callback ( undefined , results ) ;
} ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger
} ) ( service , _ . constant ( true ) ) ;
const req = {
clean : {
layers : [ non _coarse _layer , 'neighbourhood' ] ,
point : {
lat : 12.121212 ,
lon : 21.212121
}
}
} ;
const res = { } ;
// verify that next was called
const next = ( ) => {
t . pass ( 'next() should have been called' ) ;
} ;
controller ( req , res , next ) ;
const expected = {
meta : { } ,
data : [
{
_id : '10' ,
_type : 'neighbourhood' ,
layer : 'neighbourhood' ,
source : 'whosonfirst' ,
source _id : '10' ,
name : {
'default' : 'neighbourhood name'
} ,
phrase : {
'default' : 'neighbourhood name'
} ,
parent : {
neighbourhood : [ 'neighbourhood name' ] ,
neighbourhood _id : [ '10' ] ,
neighbourhood _a : [ 'neighbourhood abbr' ]
}
}
]
} ;
t . deepEquals ( req . clean . layers , [ non _coarse _layer , 'neighbourhood' ] , 'req.clean.layers should be unmodified' ) ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . ok ( next _was _called ) ;
} ) ;
t . end ( ) ;
t . end ( ) ;
} ) ;
} ) ;
@ -510,8 +780,11 @@ module.exports.tests.success_conditions = (test, common) => {
module . exports . tests . failure _conditions = ( test , common ) => {
module . exports . tests . failure _conditions = ( test , common ) => {
test ( 'service returning 0 results at the requested layer should return nothing' , ( t ) => {
test ( 'service returning 0 results at the requested layer should return nothing' , ( t ) => {
const service = ( point , do _not _track , callback ) => {
t . plan ( 4 ) ;
t . equals ( do _not _track , 'do_not_track value' ) ;
const service = ( req , callback ) => {
t . deepEquals ( req , { clean : { layers : [ 'neighbourhood' ] } } ) ;
// response without neighbourhood results
// response without neighbourhood results
const results = {
const results = {
borough : [
borough : [
@ -557,32 +830,21 @@ module.exports.tests.failure_conditions = (test, common) => {
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const logger = require ( 'pelias-mock-logger' ) ( ) ;
const should _execute = ( ) => { return true ; } ;
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
const controller = proxyquire ( '../../../controller/coarse_reverse' , {
'pelias-logger' : logger ,
'pelias-logger' : logger
'../helper/logging' : {
} ) ( service , _ . constant ( true ) ) ;
isDNT : ( ) => {
return 'do_not_track value' ;
}
}
} ) ( service , should _execute ) ;
const req = {
const req = {
clean : {
clean : {
layers : [ 'neighbourhood' ] ,
layers : [ 'neighbourhood' ]
point : {
lat : 12.121212 ,
lon : 21.212121
}
}
}
} ;
} ;
const res = { } ;
const res = { } ;
// verify that next was called
// verify that next was called
let next _was _called = false ;
const next = ( ) => {
const next = ( ) => {
next _was _called = true ;
t . pass ( 'next() was called' ) ;
} ;
} ;
controller ( req , res , next ) ;
controller ( req , res , next ) ;
@ -593,9 +855,7 @@ module.exports.tests.failure_conditions = (test, common) => {
} ;
} ;
t . deepEquals ( res , expected ) ;
t . deepEquals ( res , expected ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . notOk ( logger . hasErrorMessages ( ) ) ;
t . ok ( next _was _called ) ;
t . end ( ) ;
t . end ( ) ;
} ) ;
} ) ;