2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package com.att.bpm.scripts;
23 import groovy.xml.XmlUtil
26 import org.openecomp.mso.bpmn.core.json.JsonUtils
27 import org.openecomp.mso.bpmn.core.WorkflowException
28 import org.openecomp.mso.rest.APIResponse
29 import org.openecomp.mso.rest.RESTClient
30 import org.openecomp.mso.rest.RESTConfig
32 import java.util.UUID;
33 import javax.xml.parsers.DocumentBuilder
34 import javax.xml.parsers.DocumentBuilderFactory
36 import org.camunda.bpm.engine.delegate.BpmnError
37 import org.camunda.bpm.engine.runtime.Execution
38 import org.json.JSONObject;
39 import org.apache.commons.lang3.*
40 import org.apache.commons.codec.binary.Base64;
41 import org.w3c.dom.Document
42 import org.w3c.dom.Element
43 import org.w3c.dom.Node
44 import org.w3c.dom.NodeList
45 import org.xml.sax.InputSource
46 import static org.apache.commons.lang3.StringUtils.*;
48 import org.springframework.web.util.UriUtils;
51 * This groovy class supports the <class>CreateServiceInstance.bpmn</class> process.
53 public class DeleteServiceInstanceInfra extends AbstractServiceTaskProcessor {
55 String Prefix="DELSI_"
56 ExceptionUtil exceptionUtil = new ExceptionUtil()
57 JsonUtils jsonUtil = new JsonUtils()
58 VidUtils vidUtils = new VidUtils()
61 * This method is executed during the preProcessRequest task of the <class>CreateServiceInstance.bpmn</class> process.
64 public InitializeProcessVariables(Execution execution){
65 /* Initialize all the process variables in this block */
67 execution.setVariable("DELSI_DeleteServiceInstanceJasonRequest", "")
68 execution.setVariable("DELSI_requestDetails", "")
69 execution.setVariable("DELSI_globalSubscriberId", "")
70 execution.setVariable("DELSI_serviceInstanceName", "")
71 execution.setVariable("DELSI_serviceInstanceId", "")
72 execution.setVariable("DELSI_serviceInstance", "")
73 execution.setVariable("DELSI_messageId", "")
74 execution.setVariable("DELSI_serviceType", "")
76 execution.setVariable("DELSI_queryAAISINameResponse", "")
77 execution.setVariable("DELSI_queryAAISINameCode", "")
79 execution.setVariable("DELSI_createDBRequest", "")
80 execution.setVariable("DELSI_dbResponse", "")
81 execution.setVariable("DELSI_dbReturnCode", "")
83 execution.setVariable("DELSI_createDBInfraErrorRequest", "")
84 execution.setVariable("DELSI_errorDBInfraErrorResponse", "")
85 execution.setVariable("DELSI_errorDBInfraErrorErrorCode", "")
87 execution.setVariable("DELSI_CompleteMsoProcessRequest", "")
88 execution.setVariable("DELSI_FalloutHandlerRequest", "")
89 execution.setVariable("DELSI_Success", false)
90 execution.setVariable("DELSI_unexpectedError", "")
91 execution.setVariable("DELSI_siInUse", false)
95 // **************************************************
96 // Pre or Prepare Request Section
97 // **************************************************
99 * This method is executed during the preProcessRequest task of the <class>DeleteServiceInstance.bpmn</class> process.
102 public void preProcessRequest (Execution execution) {
103 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
104 execution.setVariable("prefix",Prefix)
106 utils.log("DEBUG", " ***** Inside preProcessRequest DeleteServiceInstance Request ***** ", isDebugEnabled)
109 // initialize flow variables
110 InitializeProcessVariables(execution)
112 // check for incoming json message/input
113 String deleteServiceInstanceIncoming = execution.getVariable("bpmnRequest")
114 utils.logAudit(deleteServiceInstanceIncoming)
115 execution.setVariable("DELSI_DeleteServiceInstanceJasonRequest", deleteServiceInstanceIncoming);
118 String requestId = execution.getVariable("att-mso-request-id")
119 execution.setVariable("DELSI_requestId", requestId)
121 String serviceInstanceId = execution.getVariable("serviceInstanceId")
122 execution.setVariable("DELSI_serviceInstanceId", serviceInstanceId)
124 String requestAction = execution.getVariable("requestAction")
125 execution.setVariable("requestAction", requestAction)
127 String source = jsonUtil.getJsonValue(deleteServiceInstanceIncoming, "requestDetails.requestInfo.source")
128 execution.setVariable("DELSI_source", source)
131 // extract requestDetails
132 String xmlRequestDetails = vidUtils.getJsonRequestDetailstoXml(deleteServiceInstanceIncoming)
133 execution.setVariable("DELSI_requestDetails", xmlRequestDetails)
135 utils.log("DEBUG", "xmlRequestDetails: " + xmlRequestDetails , isDebugEnabled)
137 String xmlParameters = utils.getNodeXml(xmlRequestDetails, "requestParameters", false)
138 utils.log("DEBUG","xmlParameters: " + xmlParameters , isDebugEnabled)
140 String serviceType = jsonUtil.getJsonValue(deleteServiceInstanceIncoming, "requestDetails.requestParameters.subscriptionServiceType")
141 execution.setVariable("DELSI_serviceType", serviceType)
143 // extract globalSubscriberId
144 //String globalSubscriberId = jsonUtil.getJsonValue(deleteServiceInstanceIncoming, "requestDetails.subscriberInfo.globalSubscriberId")
147 String messageId = execution.getVariable("DELSI_messageId") // for testing
148 if (messageId == null || messageId == "") {
149 messageId = UUID.randomUUID()
150 utils.log("DEBUG", " DELSI_messageId, random generated: " + messageId, isDebugEnabled)
152 utils.log("DEBUG", " DELSI_messageId, pre-assigned: " + messageId, isDebugEnabled)
154 execution.setVariable("DELSI_messageId", messageId)
156 AaiUtil aaiUriUtil = new AaiUtil(this)
157 String aai_uri = aaiUriUtil.getBusinessCustomerUri(execution)
158 String aaiNamespace = aaiUriUtil.getNamespaceFromUri(aai_uri)
159 logDebug('AAI namespace is: ' + aaiNamespace, isDebugEnabled)
160 execution.setVariable("DELSI_aaiNamespace","${aaiNamespace}")
162 //Setting for Generic Sub Flows
163 execution.setVariable("GENGS_type", "service-instance")
165 } catch (BpmnError e) {
168 } catch (Exception ex){
169 String exceptionMessage = "Bpmn error encountered in DeleteServiceInstance flow. Unexpected from method preProcessRequest() - " + ex.getMessage()
170 exceptionUtil.buildAndThrowWorkflowException(execution, 7000, exceptionMessage)
175 public void sendSyncResponse (Execution execution) {
176 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
177 execution.setVariable("prefix",Prefix)
179 utils.log("DEBUG", " ***** Inside sendSyncResponse of DeleteServiceInstance ***** ", isDebugEnabled)
182 String requestId = execution.getVariable("att-mso-request-id")
183 String serviceInstanceId = execution.getVariable("serviceInstanceId")
185 // RESTResponse (for API Handler (APIH) Reply Task)
186 String syncResponse = """{"requestReferences":{"instanceId":"${serviceInstanceId}","requestId":"${requestId}"}}""".trim()
188 utils.log("DEBUG", " sendSynchResponse: xmlSyncResponse - " + "\n" + syncResponse, isDebugEnabled)
189 sendWorkflowResponse(execution, 202, syncResponse)
191 } catch (Exception ex) {
192 String exceptionMessage = "Bpmn error encountered in DeleteServiceInstance flow. Unexpected from method sendSyncResponse() - " + ex.getMessage()
193 exceptionUtil.buildAndThrowWorkflowException(execution, 7000, exceptionMessage)
198 public void processGetServiceInstanceResponse(Execution execution) {
199 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
200 execution.setVariable("prefix",Prefix)
202 utils.log("DEBUG", " ***** Inside processGetServiceInstanceResponse of DeleteServiceInstance ***** " , isDebugEnabled)
206 //Extract Global Sub Id
207 String messageId = execution.getVariable("DELSI_requestId")
208 String serviceInstanceId = execution.getVariable("serviceInstanceId")
209 String siRelatedLink = execution.getVariable("GENGSI_siResourceLink")
211 int custStart = siRelatedLink.indexOf("customer/")
212 int custEnd = siRelatedLink.indexOf("/service-subscriptions")
213 String globalCustId = siRelatedLink.substring(custStart + 9, custEnd)
215 execution.setVariable("DELSI_globalSubscriberId",globalCustId)
217 //Extract Service Type if not provided on request
218 String serviceType = execution.getVariable("DELSI_serviceType")
219 if(isBlank(serviceType)){
220 int serviceStart = siRelatedLink.indexOf("service-subscription/")
221 int serviceEnd = siRelatedLink.indexOf("/service-instances/")
222 String serviceTypeEncoded = siRelatedLink.substring(serviceStart + 21, serviceEnd)
224 serviceType = UriUtils.decode(serviceTypeEncoded, "UTF-8")
226 execution.setVariable("serviceType", serviceType)
228 String serviceInstanceData = execution.getVariable("DELSI_serviceInstance");
229 utils.log("DEBUG", " DELSI_serviceInstance: " + serviceInstanceData, isDebugEnabled)
231 //Confirm there are no related service instances (vnf/network or volume)
232 if (utils.nodeExists(serviceInstanceData, "relationship-list")) {
234 InputSource source = new InputSource(new StringReader(serviceInstanceData));
235 DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
236 DocumentBuilder docBuilder = docFactory.newDocumentBuilder()
237 Document serviceXml = docBuilder.parse(source)
239 NodeList nodeList = serviceXml.getElementsByTagName("relationship")
240 for (int x = 0; x < nodeList.getLength(); x++) {
241 Node node = nodeList.item(x)
242 if (node.getNodeType() == Node.ELEMENT_NODE) {
243 Element eElement = (Element) node
244 def e = eElement.getElementsByTagName("related-to").item(0).getTextContent()
245 if(e.equals("generic-vnf") || e.equals("l3-network")){
246 utils.log("DEBUG", "ServiceInstance still has relationship(s) to OpenStack.", isDebugEnabled)
247 execution.setVariable("DELSI_siInUse", true)
248 //there are relationship dependencies to this Service Instance
249 String errorMessage = " Stopped deleting Service Instance, it has dependencies. Service instance id: " + serviceInstanceId
250 utils.log("DEBUG", errorMessage, isDebugEnabled)
251 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage)
253 utils.log("DEBUG", "Relationship NOT related to OpenStack", isDebugEnabled)
259 } catch (BpmnError e) {
261 } catch (Exception excp) {
262 // try error for method block
263 String exceptionMessage = "Bpmn error encountered in DeleteServiceInstance flow in method processGetServiceInstanceResponse. Error was - " + excp.getMessage()
264 exceptionUtil.buildAndThrowWorkflowException(execution, 7000, exceptionMessage)
266 utils.log("DEBUG", " ***** Completed processGetServiceInstanceResponse of DeleteServiceInstance ***** " , isDebugEnabled)
269 // *******************************
270 // Build DB request Section
271 // *******************************
272 public void prepareDBRequest (Execution execution) {
273 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
274 execution.setVariable("prefix", Prefix)
277 utils.log("DEBUG", " ***** Inside prepareDBRequest of DeleteServiceInstance ***** ", isDebugEnabled)
279 String requestId = execution.getVariable("DELSI_requestId")
280 String statusMessage = "Service Instance successfully deleted."
282 //TODO - verify the format for Service Instance Delete,
284 """<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
287 <ns:updateInfraRequest xmlns:ns="http://com.att.mso/requestsdb">
288 <requestId>${requestId}</requestId>
289 <lastModifiedBy>BPMN</lastModifiedBy>
290 <statusMessage>${statusMessage}</statusMessage>
291 <responseBody></responseBody>
292 <requestStatus>COMPLETED</requestStatus>
293 <progress>100</progress>
295 </ns:updateInfraRequest>
297 </soapenv:Envelope>"""
299 String buildDeleteDBRequestAsString = utils.formatXml(dbRequest)
300 execution.setVariable("DELSI_createDBRequest", buildDeleteDBRequestAsString)
301 utils.logAudit(buildDeleteDBRequestAsString)
303 } catch (Exception ex) {
304 // try error in method block
305 String exceptionMessage = "Bpmn error encountered in DeleteServiceInstance flow. Unexpected Error from method prepareDBRequest() - " + ex.getMessage()
306 exceptionUtil.buildAndThrowWorkflowException(execution, 7000, exceptionMessage)
313 // *****************************************
314 // Prepare Completion request Section
315 // *****************************************
316 public void postProcessResponse (Execution execution) {
317 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
318 execution.setVariable("prefix", Prefix)
320 utils.log("DEBUG", " ***** Inside postProcessResponse of DeleteServiceInstanceInfra ***** ", isDebugEnabled)
323 // Display Success scenario for DB update Response:
324 String dbReturnCode = execution.getVariable("DELSI_dbReturnCode")
325 utils.log("DEBUG", " ***** Success DB Update Response Code : " + dbReturnCode, isDebugEnabled)
326 utils.log("DEBUG", " ***** Success DB Update Response String: " + '\n' + execution.getVariable("DELSI_dbResponse"), isDebugEnabled)
328 if (dbReturnCode == "200") {
329 String source = execution.getVariable("DELSI_source")
330 String requestId = execution.getVariable("DELSI_requestId")
332 String msoCompletionRequest =
333 """<aetgt:MsoCompletionRequest xmlns:aetgt="http://ecomp.att.com/mso/workflow/schema/v1"
334 xmlns:ns="http://ecomp.att.com/mso/request/types/v1">
335 <request-info xmlns="http://ecomp.att.com/mso/infra/vnf-request/v1">
336 <request-id>${requestId}</request-id>
337 <action>DELETE</action>
338 <source>${source}</source>
340 <aetgt:status-message>Service Instance has been deleted successfully.</aetgt:status-message>
341 <aetgt:mso-bpel-name>BPMN Service Instance action: DELETE</aetgt:mso-bpel-name>
342 </aetgt:MsoCompletionRequest>"""
345 String xmlMsoCompletionRequest = utils.formatXml(msoCompletionRequest)
347 utils.logAudit(xmlMsoCompletionRequest)
348 execution.setVariable("DELSI_Success", true)
349 execution.setVariable("DELSI_CompleteMsoProcessRequest", xmlMsoCompletionRequest)
350 utils.log("DEBUG", " SUCCESS flow, going to CompleteMsoProcess - " + "\n" + xmlMsoCompletionRequest, isDebugEnabled)
353 String exceptionMessage = "Bpmn error encountered in DeleteServiceInstanceInfra flow. Unexpected Error from DB adapter, return code: " + dbReturnCode
354 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, exceptionMessage)
358 } catch (BpmnError e) {
361 } catch (Exception ex) {
362 // try error in method block
363 String exceptionMessage = "Bpmn error encountered in DeleteServiceInstanceInfra flow. Unexpected Error from method postProcessResponse() - " + ex.getMessage()
364 exceptionUtil.buildAndThrowWorkflowException(execution, 7000, exceptionMessage)
371 // *******************************
372 // Build Error Section
373 // *******************************
374 public void prepareDBRequestError (Execution execution) {
375 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
376 execution.setVariable("prefix", Prefix)
378 utils.log("DEBUG", " ***** Inside prepareDBRequestError of DeleteServiceInstanceInfra ***** ", isDebugEnabled)
381 String requestId = execution.getVariable("DELSI_requestId")
382 String statusMessage = ""
383 if (execution.getVariable("WorkflowException") instanceof WorkflowException) {
384 WorkflowException wfe = execution.getVariable("WorkflowException")
385 statusMessage = wfe.getErrorMessage()
388 statusMessage = "Encountered Error during DeleteServiceInstanceInfra proccessing. "
391 //TODO - verify the format for Service Instance Create,
393 """<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
396 <ns:updateInfraRequest xmlns:ns="http://com.att.mso/requestsdb">
397 <requestId>${requestId}</requestId>
398 <lastModifiedBy>BPMN</lastModifiedBy>
399 <statusMessage>${statusMessage}</statusMessage>
400 <responseBody></responseBody>
401 <requestStatus>FAILED</requestStatus>
403 </ns:updateInfraRequest>
405 </soapenv:Envelope>"""
407 String buildDBRequestAsString = utils.formatXml(dbRequest)
408 execution.setVariable("DELSI_createDBInfraErrorRequest", buildDBRequestAsString)
409 utils.logAudit(buildDBRequestAsString)
411 } catch (Exception ex) {
412 // try error in method block
413 String exceptionMessage = "Bpmn error encountered in DeleteServiceInstanceInfra flow. Unexpected Error from method prepareDBRequestError() - " + ex.getMessage()
414 exceptionUtil.buildWorkflowException(execution, 7000, exceptionMessage)
420 // Prepare for FalloutHandler
421 public void buildErrorResponse (Execution execution) {
422 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
423 execution.setVariable("prefix", Prefix)
425 utils.log("ERROR", " ***** Prepare for FalloutHandler. FAILURE - prepare request for sub-process FalloutHandler. *****", isDebugEnabled)
427 String falloutHandlerRequest = ""
429 // Display Success scenario for DB update Response:
430 String dbReturnCode = execution.getVariable("DELSI_errorDBInfraErrorErrorCode")
431 utils.log("DEBUG", " ***** Error DB Update Response Code : " + dbReturnCode, isDebugEnabled)
432 utils.log("DEBUG", " ***** Error DB Update Response String: " + '\n' + execution.getVariable("DELSI_errorDBInfraErrorResponse"), isDebugEnabled)
434 String requestId = execution.getVariable("DELSI_requestId")
435 String source = execution.getVariable("DELSI_source")
437 execution.setVariable("DELSI_Success", false)
438 String errorMessage = ""
439 String errorCode = ""
441 if (execution.getVariable("WorkflowException") instanceof WorkflowException) {
442 WorkflowException wfe = execution.getVariable("WorkflowException")
443 errorMessage = wfe.getErrorMessage()
444 errorCode = wfe.getErrorCode().toString()
447 errorMessage = "Bpmn error encountered in DeleteServiceInstanceInfra flow."
452 falloutHandlerRequest =
453 """<aetgt:FalloutHandlerRequest xmlns:aetgt="http://ecomp.att.com/mso/workflow/schema/v1"
454 xmlns:ns="http://ecomp.att.com/mso/request/types/v1"
455 xmlns:wfsch="http://ecomp.att.com/mso/workflow/schema/v1">
456 <request-info xmlns="http://ecomp.att.com/mso/infra/vnf-request/v1">
457 <request-id>${requestId}</request-id>
458 <action>DELETE</action>
459 <source>${source}</source>
461 <aetgt:WorkflowException xmlns:aetgt="http://ecomp.att.com/mso/workflow/schema/v1">
462 <aetgt:ErrorMessage>${errorMessage}</aetgt:ErrorMessage>
463 <aetgt:ErrorCode>${errorCode}</aetgt:ErrorCode>
464 </aetgt:WorkflowException>
465 </aetgt:FalloutHandlerRequest>"""
467 utils.logAudit(falloutHandlerRequest)
468 execution.setVariable("DELSI_FalloutHandlerRequest", falloutHandlerRequest)
469 utils.log("ERROR", " Overall Error Response going to FalloutHandler: " + "\n" + falloutHandlerRequest, isDebugEnabled)
471 } catch (Exception ex) {
472 // rebuild workflow exception
473 String requestId = execution.getVariable("DELSI_requestId")
474 String source = execution.getVariable("DELSI_source")
475 String errorException = " Build Error Response exception encountered during method buildErrorResponse(), preparing request for FalloutHandler: - " + ex.getMessage()
476 utils.log("DEBUG", errorException, isDebugEnabled)
477 falloutHandlerRequest =
478 """<aetgt:FalloutHandlerRequest xmlns:aetgt="http://ecomp.att.com/mso/workflow/schema/v1"
479 xmlns:ns="http://ecomp.att.com/mso/request/types/v1"
480 xmlns:wfsch="http://ecomp.att.com/mso/workflow/schema/v1">
481 <request-info xmlns="http://ecomp.att.com/mso/infra/vnf-request/v1">
482 <request-id>${requestId}</request-id>
483 <action>DELETE</action>
484 <source>${source}</source>
486 <aetgt:WorkflowException xmlns:aetgt="http://ecomp.att.com/mso/workflow/schema/v1">
487 <aetgt:ErrorMessage>${errorException}</aetgt:ErrorMessage>
488 <aetgt:ErrorCode>7000</aetgt:ErrorCode>
489 </aetgt:WorkflowException>
490 </aetgt:FalloutHandlerRequest>"""
491 execution.setVariable("DELSI_FalloutHandlerRequest", falloutHandlerRequest)
492 utils.log("ERROR", " Overall Error Response going to FalloutHandler: " + "\n" + falloutHandlerRequest, isDebugEnabled)
498 public void sendSyncError (Execution execution) {
499 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
500 execution.setVariable("prefix", Prefix)
502 utils.log("DEBUG", " ***** Inside sendSyncError() of DeleteServiceInstanceInfra ***** ", isDebugEnabled)
505 String errorMessage = ""
506 if (execution.getVariable("WorkflowException") instanceof WorkflowException) {
507 WorkflowException wfe = execution.getVariable("WorkflowException")
508 errorMessage = wfe.getErrorMessage()
510 errorMessage = "Sending Sync Error."
513 String buildworkflowException =
514 """<aetgt:WorkflowException xmlns:aetgt="http://ecomp.att.com/mso/workflow/schema/v1">
515 <aetgt:ErrorMessage>${errorMessage}</aetgt:ErrorMessage>
516 <aetgt:ErrorCode>7000</aetgt:ErrorCode>
517 </aetgt:WorkflowException>"""
519 utils.logAudit(buildworkflowException)
520 sendWorkflowResponse(execution, 500, buildworkflowException)
523 } catch (Exception ex) {
524 utils.log("DEBUG", " Sending Sync Error Activity Failed. " + "\n" + ex.getMessage(), isDebugEnabled)
529 public void processJavaException(Execution execution){
530 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
531 execution.setVariable("prefix",Prefix)
533 utils.log("DEBUG", "Caught a Java Exception", isDebugEnabled)
534 utils.log("DEBUG", "Started processJavaException Method", isDebugEnabled)
535 utils.log("DEBUG", "Variables List: " + execution.getVariables(), isDebugEnabled)
536 execution.setVariable("DELSI_unexpectedError", "Caught a Java Lang Exception") // Adding this line temporarily until this flows error handling gets updated
537 exceptionUtil.buildAndThrowWorkflowException(execution, 500, "Caught a Java Lang Exception")
539 utils.log("ERROR", "Rethrowing MSOWorkflowException", isDebugEnabled)
542 utils.log("DEBUG", "Caught Exception during processJavaException Method: " + e, isDebugEnabled)
543 execution.setVariable("DELSI_unexpectedError", "Exception in processJavaException method") // Adding this line temporarily until this flows error handling gets updated
544 exceptionUtil.buildAndThrowWorkflowException(execution, 500, "Exception in processJavaException method")
546 utils.log("DEBUG", "Completed processJavaException Method", isDebugEnabled)