describe("Test Controller CustomActionEditorController", function() { 'use strict'; var scope, screenConfigurationModel, systemAlertService, $e, screenObj, $q, modalInstance, createController, providerActionList; beforeEach(module('myitsmApp')); beforeEach(module('adminModule')); beforeEach(inject(function ($rootScope, $controller, $injector, _screenConfigurationModel_, _systemAlertService_, _$q_, $httpBackend) { $httpBackend = $injector.get('$httpBackend'); var getLocale = function () { return readJSON('scripts/app/i18n/resources-locale_en.json'); }; $httpBackend.whenGET(/^scripts\/app\/i18n\/resources-locale_en.*$/).respond(getLocale()); $httpBackend.whenGET('/smartit/rest/serverstates').respond(200); $httpBackend.whenGET('/smartit/rest/sessionstatus?getLicenseKey=true').respond(200); $httpBackend.whenGET('/smartit/rest/customization/available/accelerators?datasource=global').respond(200); $httpBackend.whenGET('/smartit/rest/action/search?resourceType=global').respond(200); $httpBackend.whenGET('views/dashboard/index.html').respond(200); scope = $rootScope.$new(); screenConfigurationModel = _screenConfigurationModel_; systemAlertService = _systemAlertService_; scope.acceleratorsList = []; scope.providerFieldList = []; scope.actionList = []; scope.isTemplateLoaded = false; scope.accelerators = { expression : '', showAcceleratorsList: false}; scope.acceleratorList = []; scope.actionObj = {}; scope.resouceType = EntityVO.TYPE_INCIDENT; scope.hasInputFields = false; scope.hasOutputFields = false; $q = _$q_; var actionList = [ { "items": [ { "actionOrder": "alphabetical", "resourceType": "asset", "actionList": [ { "resource": "asset", "actionType": "launch", "supportedPlatforms": [ "web" ], "target": "new", "sequenceNo": 1, "scope": { "assetClass": { "ALL": true } }, "subActions": [ { "resource": "asset", "name": "assetUpdate", "fields": [ "partNumber" ], "id": "93eabe11-2000-4564-8abc-c6e17db31f1e" } ], "labels": { "default": "dasd" }, "tenantId": "000000000000001", "id": "32d2f52f-6696-46d5-a588-03b1f2d4eff1" } ] } ], "numMatch": 1, "syncTime": 1523279185490, "dataSourceName": "Action" } ], dataMap = { "serviceType": "Incident Type*", "contactCompany": "Direct Contact Company", "customerPersonId": "Person ID", "contactFirstName": "Direct Contact First Name", "resolution": "Resolution", "productName": "Product Name+", "resProductCategoryTier2": "Resolution Product Categorization Tier 2", "resProductCategoryTier1": "Resolution Product Categorization Tier 1", "statusReason": "Status_Reason_Hidden", "assigneeLoginId": "Assignee Login ID", "resProductCategoryTier3": "Resolution Product Categorization Tier 3", "resProductName": "Product Name (R)+", "id": "Incident ID*+", "siteGroup": "Site Group", "supportGroups": "Assigned Group*+", "CI_reconid": "HPD_CI_ReconID", "impact": "Impact*", "impactedService": "Service*+", "priority": "Priority*", "assignedSupportCompany": "Assigned Support Company", "firstName": "First Name+", "phoneNumber": "Customer Phone*+", "causalCI": "CI+", "contactLastName": "Direct Contact Last Name", "contactPhoneNumber": "Contact Phone+", "assignee": "Assignee+", "region": "Region", "desc": "Notes", "status": "Status*", "customerLoginId": "Customer Login ID", "lastName": "Last Name+", "resOperationCategoryTier3": "Resolution Categorization Tier 3", "locationCompany": "Company", "resOperationCategoryTier2": "Resolution Categorization Tier 2", "resOperationCategoryTier1": "Resolution Categorization Tier 1", "customerVIPFlag": "VIP", "urgency": "Urgency*", "operationCategoryTier3": "Operational Categorization Tier 3", "company": "Company*+", "contactLoginId": "Direct Contact Login ID", "operationCategoryTier2": "Operational Categorization Tier 2", "operationCategoryTier1": "Operational Categorization Tier 1+", "summary": "Summary*", "assignedGroup": "Assigned Group ID", "contactOrganization": "Direct Contact Organization", "contactEmail": "Direct Contact Internet E-mail", "serviceCIReconId": "ServiceCI_ReconID", "resProductModelVersion": "Model/Version (R)", "site": "Customer Site", "internetEmail": "Internet E-mail", "organization": "Organization", "productCategoryTier3": "Product Categorization Tier 3", "productCategoryTier1": "Product Categorization Tier 1", "productCategoryTier2": "Product Categorization Tier 2", "productModelVersion": "Model/Version", "assignedSupportOrganization^": "Assigned Support Organization" }; providerActionList = [ new ActionVO().build({ "resource": "incident", "actionType": "provider", "actionName": "PA_CHG_OTB_TO_OTB", "supportedPlatforms": [ "web" ], "url": "", "labels": { "default": "PA_CHG_OTB_TO_OTB_Label" }, "sequenceNo": 1, "mode": "both", "isOpen": false, "delete": false, "screenId": "AGGAA5V0HG8SIAOSYVXNABCS8RNIK3", "templateId": "IDGAA5V0HGVEGAP76I3VP69HQE2RGW", "actionOrder": "", "mappings": [ { "type": "input-ticket", "mappedFieldId": 1000000151, "mappedFieldValue": "summary" }, { "type": "output", "mappedFieldId": 1000000000, "mappedFieldValue": "desc" } ], "isExpression": false, "expressions": [ { "resource": "incident", "executeOn": "On Field Value Change", "condition": "$priority == 'High'", "sequenceNo": 1 } ], "mappedFields": [], "entryId": "000000000000001", "formName": "CHG:Infrastructure Change", "isSynchronous": true, "id": "AGGAA5V0HGVEGAP76IK2P69HWL2RJT", "label": "PA_CHG_OTB_TO_OTB_Label" }) ]; screenObj = { "id": "AGGAA5V0HG8SIAOSYVXNABCS8RNIK3", "name": "incidentViewScreen", "datasource": "incident", }; modalInstance = { // Create a mock object using spies open: jasmine.createSpy('modalInstance.open'), close: jasmine.createSpy('modalInstance.close'), dismiss: jasmine.createSpy('modalInstance.dismiss'), hide: jasmine.createSpy('modalInstance.hide'), result: { then: jasmine.createSpy('modalInstance.result.then') } }; scope.sortableOptions = { update: function (e, ui) { if ($scope.actionOrder !== 'custom') { ui.item.sortable.cancel(); } }, stop: function () { // update field ordering $scope.actionList.forEach(function (action, index) { action.sequenceNo = index + 1; }); } }; spyOn(screenConfigurationModel, 'saveActionConfiguration').and.callFake(function () { let deferred = $q.defer(); deferred.resolve(actionList); return deferred.promise; }); spyOn(screenConfigurationModel, 'getTemplateList').and.callFake(function () { let deferred = $q.defer(); deferred.resolve([]); return deferred.promise; }); spyOn(screenConfigurationModel, 'getTemplateById').and.callFake(function () { let deferred = $q.defer(); deferred.resolve({}); return deferred.promise; }); spyOn(screenConfigurationModel, 'getAccelerators').and.callFake(function () { let deferred = $q.defer(); deferred.resolve(dataMap); return deferred.promise; }); spyOn(screenConfigurationModel, 'loadActions').and.callFake(function () { let deferred = $q.defer(); deferred.resolve([]); return deferred.promise; }); spyOn(screenConfigurationModel, 'loadActionsNew').and.callFake(function () { let deferred = $q.defer(); screenConfigurationModel.actionList = providerActionList; screenConfigurationModel.actionOrder = "alphabetical"; deferred.resolve([]); return deferred.promise; }); createController = function() { return $controller('CustomActionEditorController', { '$scope': scope, '$modalInstance': modalInstance, 'screenObj' : new ScreenConfigurationVO().build(screenObj) }); }; })); it(' should run handleBodyKeyDown method ',function() { createController(); scope.openActionItem = {url:'www.google.com'}; scope.handleBodyKeyDown({target:{value:'[1234'},key: '['}); expect(scope.accelerators.showAcceleratorsList).toBeTruthy(); }); it(' should run handleBodyChange method ',function(){ createController(); var actionObj = new ActionVO(); scope.accelerators.showAcceleratorsList = false; actionObj.url = 'http://www.bmc.com'; scope.openActionItem = actionObj; scope.handleBodyChange({target:{value:'[1234',selectionEnd:0}}); scope.handleBodyChange({target:{value:'[1234',selectionEnd:0}, ctrlKey:true}); scope.handleBodyChange({target:{value:'[1234',selectionEnd:0}, keyCode :38}); scope.handleBodyChange({target:{value:'[1234',selectionEnd:0}, keyCode :40}); scope.acceleratorsList[{name:'dummy',value:'dummy'}]; scope.handleBodyChange({target:{value:'[1234',selectionEnd:0}, keyCode :27}); scope.accelerators.showAcceleratorsList = true; scope.accelerators.expression = 'anything'; scope.handleBodyChange({target:{value:'1234',selectionEnd:0}, keyCode :9}); expect(scope.accelerators.showAcceleratorsList).toBeTruthy(); }); it(' should run handleBodyClick method ',function() { createController(); scope.handleBodyClick({target:{value:'[1234', selectionEnd:0}}); expect(scope.accelerators.showAcceleratorsList).toBeFalsy(); }); it(' should run acceleratorMouseover method ',function() { createController(); scope.acceleratorMouseover({index:123}); expect(scope.typeAheadListPos).toEqual({index:123}); }); it(' should run insertAcceleratorText method ',function() { createController(); var actionObj = new ActionVO(); scope.accelerators.showAcceleratorsList = false; actionObj.url = 'http://www.bmc.com'; scope.openActionItem = actionObj; scope.handleBodyChange({target:{value:'[1234',selectionEnd:0}}); scope.accelerators.expression = true; scope.insertAcceleratorText({name:'TestAccelerator'}); expect(!!scope.accelerators.expression).toBeFalsy(); scope.accelerators.expression = true; scope.insertAcceleratorText({name:'TestAccelerator'}); expect(scope.accelerators.expression).toEqual(''); }); it(' should run hideTypeAheadPopup method ',function() { createController(); scope.hideTypeAheadPopup(); }); it(' should run sortableOptions method ',function() { createController(); scope.actionList = [{},{}]; scope.sortableOptions.stop(); scope.actionOrder = 'custom'; scope.sortableOptions.update({},{}); }); it(' should run onCancelClick method ',function() { createController(); scope.onCancelClick(); }); it(' should run onSaveClick method ',function() { createController(); var actionObj = new ActionVO(); actionObj.actionType = 'client'; actionObj.actionName = 'providerAction'; actionObj.url = 'http://www.bmc.com'; actionObj.label = 'TestURL'; actionObj.delete = false; scope.actionList = [actionObj]; scope.resouceType = EntityVO.TYPE_INCIDENT; scope.onSaveClick(); var actionObj2 = new ActionVO(); actionObj2.actionType = 'launch'; scope.resouceType = EntityVO.TYPE_ASSET; scope.actionList = [actionObj2]; scope.onSaveClick(); scope.resouceType = EntityVO.TYPE_CHANGE; scope.onSaveClick(); expect(scope.actionList.length).toEqual(1); var actionObj3 = new ActionVO(); actionObj3.actionType = 'provider'; actionObj3.actionName = 'providerAction'; actionObj3.labels = {default: 'PA'}; scope.resouceType = EntityVO.TYPE_INCIDENT; actionObj3.expressions = [{ condition: "$status == 'Assigned'", resource: 'incident', sequenceNo: 0, executeOn: 'On Ticket Load' }]; scope.actionList = [actionObj3]; scope.onSaveClick(); scope.resouceType = EntityVO.TYPE_ASSET; var actionObj4 = new ActionVO(); actionObj4.actionType = 'launch'; actionObj4.actionName = 'AssetAction'; actionObj4.subAction = [ {resource: "asset", name: "assetUpdate", fields: ["partNumber"]} ]; actionObj4.supportedPlatforms = ["web"]; actionObj4.scope = {"assetClass":{"ALL":true}}; actionObj4.delete = false; scope.actionOrder = 'alphabetical'; scope.onSaveClick(); var postActionList = []; screenConfigurationModel.saveActionConfiguration(postActionList, scope.actionOrder, scope.resouceType).then(function () { expect(screenConfigurationModel.loadActionsForRuntime).toHaveBeenCalled(); }); }); it(' should run reOrderActionList method ',function(){ createController(); scope.reOrderActionList('custom'); expect(scope.actionOrder).toEqual('custom'); scope.reOrderActionList('other'); expect(scope.actionOrder).toEqual('other'); }); it(' should run closeAllAction method ',function(){ createController(); scope.closeAllAction(); }); it(' should run openAction method ',function(){ createController(); var actionObj = new ActionVO(); scope.openAction(actionObj); expect(scope.openActionItem.isOpen).toBeTruthy(); }); it(' should run createAction method ',function(){ createController(); scope.createAction(); expect(scope.openActionItem.isOpen).toBeTruthy(); }); it(' should run addLabel method ',function(){ createController(); var actionObj = new ActionVO(); scope.resouceType = 'incident'; scope.addLabel(actionObj); expect(scope.actionObj.labels).not.toBeDefined(); }); it(' should run removeLabel method ',function(){ createController(); var actionObj = new ActionVO(); scope.removeLabel(actionObj); expect(scope.actionObj.labels).not.toBeDefined(); }); it(' should run updateLabel method ',function(){ createController(); var actionObj = new ActionVO(); scope.updateLabel(actionObj,'test','en'); expect(scope.actionObj.labels).not.toBeDefined(); }); it(' should run deleteAction method ',function(){ createController(); var actionObj = new ActionVO(); $e = document.createEvent("HTMLEvents"); scope.deleteAction($e,actionObj); }); it(' should run toggleSupportedType method ',function(){ createController(); var actionObj = new ActionVO(); scope.toggleSupportedType(actionObj, 'web'); }); it(' should run toggleUserInput method ',function(){ createController(); var actionObj = new ActionVO(); actionObj.subActions = []; scope.toggleUserInput(actionObj, 'assetUpdate'); }); it(' should run checkItem method ',function(){ createController(); var actionObj = new ActionVO(); actionObj.scope = {assetClass:{}}; scope.checkItem(actionObj,{label:'computer'},{}); }); it(' should run addAssetFieldToUpdate method ',function(){ createController(); var actionObj = new ActionVO(); scope.addAssetFieldToUpdate(actionObj, 'test'); }); it(' should run checkAll method ',function(){ createController(); var actionObj = new ActionVO(); actionObj.scope = {assetClass:{}}; scope.checkAll(actionObj); }); it(' should run loadAcceleratorList method ',function(){ createController(); scope.loadAcceleratorList('template'); }); it(' should run onTemplateSelect method ',function(){ createController(); scope.onTemplateSelect({id:'XYZ23423423'}); }); it(' should run updateFieldType method ',function(){ createController(); var field = new FieldVO(); field.id = 3212; field.label = 'test'; scope.updateFieldType(field,'test'); expect(field.mappedSource).toEqual('test'); }); it(' should run getFieldLabel method ',function(){ createController(); var label = scope.getFieldLabel(3212); expect(label).toBeDefined(); }); it(' should initialize the controller and load accelerators and check for any special characters also',function() { scope.resouceType = EntityVO.TYPE_INCIDENT; createController(); scope.$apply(); expect(scope.acceleratorsListForExpressions.length).toBe(56); expect(scope.acceleratorsListForExpressions[0].name).toBe('$CI_reconid'); expect(scope.acceleratorsListForExpressions[55].name).toBe("'$assignedSupportOrganization^'"); }); it(' should initialize the controller and load existing provider action having expression condition in case of incident',function() { scope.resouceType = EntityVO.TYPE_INCIDENT; createController(); scope.$apply(); expect(scope.screenObj.name).toBe('incidentViewScreen'); expect(scope.resouceType).toBe('incident'); expect(scope.actionList.length).toBe(1); expect(scope.actionOrder).toBe('alphabetical'); expect(scope.actionList[0].expressionCondition).toBe(scope.actionList[0].expressions[0].condition); expect(scope.actionList[0].selectedExecuteOnProperty.name).toBe(scope.providerActionExecuteOnPropOptions[0].name); expect(scope.actionList[0].showExecuteOn).toBeTruthy(); expect(scope.isExpressionDrivenAction).toBeTruthy(); }); it(' should initialize the controller and load existing provider action having expression condition in case of change',function() { providerActionList[0].resource = providerActionList[0].expressions[0].resource = scope.resouceType = EntityVO.TYPE_CHANGE; screenObj = { "id": "AGGAA5V0HG8SIAOSYVXNABCS8RNIK3", "name": "changeViewScreen", "datasource": "change", }; createController(); scope.$apply(); expect(scope.screenObj.name).toBe('changeViewScreen'); expect(scope.resouceType).toBe('change'); expect(scope.actionList.length).toBe(1); expect(scope.actionOrder).toBe('alphabetical'); expect(scope.actionList[0].expressionCondition).toBe(scope.actionList[0].expressions[0].condition); expect(scope.actionList[0].selectedExecuteOnProperty.name).toBe(scope.providerActionExecuteOnPropOptions[0].name); expect(scope.actionList[0].showExecuteOn).toBeTruthy(); expect(scope.isExpressionDrivenAction).toBeTruthy(); }); it(' should initialize the controller and load existing provider action having expression condition in case of workorder',function() { providerActionList[0].resource = providerActionList[0].expressions[0].resource = scope.resouceType = EntityVO.TYPE_CHANGE; screenObj = { "id": "AGGAA5V0HG8SIAOSYVXNABCS8RNIK3", "name": "workOrderViewScreen", "datasource": "workorder", }; createController(); scope.$apply(); expect(scope.screenObj.name).toBe('workOrderViewScreen'); expect(scope.resouceType).toBe('workorder'); expect(scope.actionList.length).toBe(1); expect(scope.actionOrder).toBe('alphabetical'); expect(scope.actionList[0].expressionCondition).toBe(scope.actionList[0].expressions[0].condition); expect(scope.actionList[0].selectedExecuteOnProperty.name).toBe(scope.providerActionExecuteOnPropOptions[0].name); expect(scope.actionList[0].showExecuteOn).toBeTruthy(); expect(scope.isExpressionDrivenAction).toBeTruthy(); }); it(' should initialize the controller and load existing provider action having expression condition in case of task',function() { providerActionList[0].resource = providerActionList[0].expressions[0].resource = scope.resouceType = EntityVO.TYPE_CHANGE; screenObj = { "id": "AGGAA5V0HG8SIAOSYVXNABCS8RNIK3", "name": "taskViewScreen", "datasource": "task", }; createController(); scope.$apply(); expect(scope.screenObj.name).toBe('taskViewScreen'); expect(scope.resouceType).toBe('task'); expect(scope.actionList.length).toBe(1); expect(scope.actionOrder).toBe('alphabetical'); expect(scope.actionList[0].expressionCondition).toBe(scope.actionList[0].expressions[0].condition); expect(scope.actionList[0].selectedExecuteOnProperty.name).toBe(scope.providerActionExecuteOnPropOptions[0].name); expect(scope.actionList[0].showExecuteOn).toBeTruthy(); expect(scope.isExpressionDrivenAction).toBeTruthy(); }); it(' should initialize the controller and load existing provider action which does not have expression condition',function() { scope.resouceType = EntityVO.TYPE_INCIDENT; providerActionList[0].expressions = []; createController(); scope.$apply(); expect(scope.screenObj.name).toBe('incidentViewScreen'); expect(scope.resouceType).toBe('incident'); expect(scope.actionList.length).toBe(1); expect(scope.actionOrder).toBe('alphabetical'); expect(scope.actionList[0].expressionCondition).toBe(''); expect(scope.actionList[0].selectedExecuteOnProperty.name).toBe(scope.providerActionExecuteOnPropOptions[0].name); expect(scope.actionList[0].showExecuteOn).toBeFalsy(); expect(scope.isExpressionDrivenAction).toBeTruthy(); }); it(' should not show execute checkbox option in case of ticket other than incident, work order, task and change',function() { scope.resouceType = EntityVO.TYPE_KNOWNERROR; screenObj = { "id": "AGGAA5V0HG8SIAOSYVXNABCS8RNIK3", "name": "knownErrorViewScreen", "datasource": "knownError", }; createController(); scope.$apply(); expect(scope.isExpressionDrivenAction).toBeUndefined(); }); it(' should remove the expression condition if Execute On checkbox is unchecked',function() { var actionObj = { showExecuteOn: false, expressionCondition: "$contactFirstName == 'Allen'" }; scope.resouceType = EntityVO.TYPE_INCIDENT; createController(); scope.$apply(); scope.toggleExecuteOn(actionObj); expect(actionObj.expressionCondition).toBe(null); }); describe('should save the provider action on click of save button ', function () { beforeEach(function () { spyOn(screenConfigurationModel, 'createUrlAction').and.callFake(function () { let deferred = $q.defer(); screenConfigurationModel.actionList = providerActionList; screenConfigurationModel.actionOrder = "alphabetical"; deferred.resolve(true); return deferred.promise; }); spyOn(screenConfigurationModel, 'loadActionsForRuntimeV2').and.callFake(function () { let deferred = $q.defer(); deferred.resolve(true); return deferred.promise; }); spyOn(systemAlertService, 'success'); scope.resouceType = EntityVO.TYPE_INCIDENT; }); it('having expression condition',function() { createController(); scope.$apply(); scope.templateList = [ { "id": "IDGAA5V0HGVEGAP76I3VP69HQE2RGW", "name": "PA_CHG_OTB_TO_OTB", "formName": "CHG:Infrastructure Change", "mappings": [ { "type": "input", "mappedFieldId": 1000000151, "mappedFieldName": "Detailed Description" }, { "type": "output", "mappedFieldId": 1000000000, "mappedFieldName": "Description" } ] } ]; expect(scope.actionList[0].expressionCondition).toBe("$priority == 'High'"); scope.onSaveClick(); scope.$apply(); expect(scope.actionList[0].expressions[0].condition).toBe("$priority == 'High'"); expect(scope.actionList[0].expressionCondition).toBeUndefined(); expect(scope.actionList[0].expressions[0].executeOn).toBe(scope.actionList[0].selectedExecuteOnProperty.value); expect(screenConfigurationModel.createUrlAction).toHaveBeenCalled(); expect(systemAlertService.success).toHaveBeenCalled(); expect(modalInstance.dismiss).toHaveBeenCalled(); expect(screenConfigurationModel.loadActionsForRuntimeV2).toHaveBeenCalledWith('incident', true); }); it('having no expression condition',function() { providerActionList[0].expressions = []; createController(); scope.$apply(); scope.templateList = [ { "id": "IDGAA5V0HGVEGAP76I3VP69HQE2RGW", "name": "PA_CHG_OTB_TO_OTB", "formName": "CHG:Infrastructure Change", "mappings": [ { "type": "input", "mappedFieldId": 1000000151, "mappedFieldName": "Detailed Description" }, { "type": "output", "mappedFieldId": 1000000000, "mappedFieldName": "Description" } ] } ]; scope.onSaveClick(); scope.$apply(); expect(scope.actionList[0].expressions).toBeUndefined(); expect(scope.actionList[0].expressionCondition).toBeUndefined(); expect(screenConfigurationModel.createUrlAction).toHaveBeenCalled(); expect(systemAlertService.success).toHaveBeenCalled(); expect(modalInstance.dismiss).toHaveBeenCalled(); expect(screenConfigurationModel.loadActionsForRuntimeV2).toHaveBeenCalledWith('incident', true); }); it('having expression condition but no expressions',function() { providerActionList[0].expressions = null; createController(); scope.$apply(); scope.templateList = [ { "id": "IDGAA5V0HGVEGAP76I3VP69HQE2RGW", "name": "PA_CHG_OTB_TO_OTB", "formName": "CHG:Infrastructure Change", "mappings": [ { "type": "input", "mappedFieldId": 1000000151, "mappedFieldName": "Detailed Description" }, { "type": "output", "mappedFieldId": 1000000000, "mappedFieldName": "Description" } ] } ]; providerActionList[0].expressionCondition = "$priority == 'High'"; expect(scope.actionList[0].expressions).toBe(null); expect(scope.actionList[0].expressionCondition).toBe("$priority == 'High'"); scope.onSaveClick(); scope.$apply(); expect(scope.actionList[0].expressions.length).toBe(1); expect(scope.actionList[0].expressionCondition).toBeUndefined(); expect(screenConfigurationModel.createUrlAction).toHaveBeenCalled(); expect(systemAlertService.success).toHaveBeenCalled(); expect(modalInstance.dismiss).toHaveBeenCalled(); expect(screenConfigurationModel.loadActionsForRuntimeV2).toHaveBeenCalledWith('incident', true); }); }); });