001// -------------------------------------------------------------------------------- 002// Copyright 2002-2025 Echo Three, LLC 003// 004// Licensed under the Apache License, Version 2.0 (the "License"); 005// you may not use this file except in compliance with the License. 006// You may obtain a copy of the License at 007// 008// http://www.apache.org/licenses/LICENSE-2.0 009// 010// Unless required by applicable law or agreed to in writing, software 011// distributed under the License is distributed on an "AS IS" BASIS, 012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013// See the License for the specific language governing permissions and 014// limitations under the License. 015// -------------------------------------------------------------------------------- 016 017package com.echothree.control.user.core.server.command; 018 019import com.echothree.control.user.core.common.edit.EntityAttributeEdit; 020import com.echothree.control.user.core.common.form.CreateEntityAttributeForm; 021import com.echothree.control.user.core.common.result.CoreResultFactory; 022import com.echothree.model.control.core.common.EntityAttributeTypes; 023import com.echothree.model.control.core.server.logic.EntityAttributeLogic; 024import com.echothree.model.control.core.server.logic.EntityTypeLogic; 025import com.echothree.model.control.party.common.PartyTypes; 026import com.echothree.model.control.security.common.SecurityRoleGroups; 027import com.echothree.model.control.security.common.SecurityRoles; 028import com.echothree.model.control.sequence.common.SequenceTypes; 029import com.echothree.model.control.sequence.server.control.SequenceControl; 030import com.echothree.model.control.sequence.server.logic.SequenceTypeLogic; 031import com.echothree.model.control.uom.server.logic.UnitOfMeasureTypeLogic; 032import com.echothree.model.control.workflow.server.logic.WorkflowLogic; 033import com.echothree.model.data.core.server.entity.EntityAttribute; 034import com.echothree.model.data.core.server.entity.EntityAttributeType; 035import com.echothree.model.data.sequence.server.entity.Sequence; 036import com.echothree.model.data.uom.server.entity.UnitOfMeasureType; 037import com.echothree.model.data.user.common.pk.UserVisitPK; 038import com.echothree.model.data.workflow.server.entity.Workflow; 039import com.echothree.util.common.command.BaseResult; 040import com.echothree.util.common.form.ValidationResult; 041import com.echothree.util.common.message.ExecutionErrors; 042import com.echothree.util.common.validation.FieldDefinition; 043import com.echothree.util.common.validation.FieldType; 044import com.echothree.util.server.control.BaseSimpleCommand; 045import com.echothree.util.server.control.CommandSecurityDefinition; 046import com.echothree.util.server.control.PartyTypeDefinition; 047import com.echothree.util.server.control.SecurityRoleDefinition; 048import com.echothree.util.server.persistence.Session; 049import com.echothree.util.server.validation.Validator; 050import java.util.List; 051import javax.enterprise.context.RequestScoped; 052 053@RequestScoped 054public class CreateEntityAttributeCommand 055 extends BaseSimpleCommand<CreateEntityAttributeForm> { 056 057 private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION; 058 private final static List<FieldDefinition> FORM_FIELD_DEFINITIONS; 059 060 private final static List<FieldDefinition> BLOB_FORM_FIELD_DEFINITIONS; 061 private final static List<FieldDefinition> STRING_FORM_FIELD_DEFINITIONS; 062 private final static List<FieldDefinition> INTEGER_FORM_FIELD_DEFINITIONS; 063 private final static List<FieldDefinition> LONG_FORM_FIELD_DEFINITIONS; 064 private final static List<FieldDefinition> LISTITEM_FORM_FIELD_DEFINITIONS; 065 private final static List<FieldDefinition> MULTIPLELISTITEM_FORM_FIELD_DEFINITIONS; 066 private final static List<FieldDefinition> WORKFLOW_FORM_FIELD_DEFINITIONS; 067 private final static List<FieldDefinition> OTHER_FORM_FIELD_DEFINITIONS; 068 069 static { 070 COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of( 071 new PartyTypeDefinition(PartyTypes.UTILITY.name(), null), 072 new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of( 073 new SecurityRoleDefinition(SecurityRoleGroups.EntityAttribute.name(), SecurityRoles.Create.name()) 074 )) 075 )); 076 077 FORM_FIELD_DEFINITIONS = List.of( 078 new FieldDefinition("EntityRef", FieldType.ENTITY_REF, false, null, null), 079 new FieldDefinition("Uuid", FieldType.UUID, false, null, null), 080 new FieldDefinition("ComponentVendorName", FieldType.ENTITY_NAME, false, null, null), 081 new FieldDefinition("EntityTypeName", FieldType.ENTITY_TYPE_NAME, false, null, null), 082 new FieldDefinition("EntityAttributeName", FieldType.ENTITY_NAME, false, null, null), 083 new FieldDefinition("EntityAttributeTypeName", FieldType.ENTITY_NAME, true, null, null), 084 new FieldDefinition("TrackRevisions", FieldType.BOOLEAN, true, null, null), 085 new FieldDefinition("SortOrder", FieldType.SIGNED_INTEGER, true, null, null), 086 new FieldDefinition("Description", FieldType.STRING, false, 1L, 132L) 087 ); 088 089 BLOB_FORM_FIELD_DEFINITIONS = List.of( 090 new FieldDefinition("CheckContentWebAddress", FieldType.BOOLEAN, true, null, null), 091 new FieldDefinition("ValidationPattern", FieldType.NULL, false, null, null), 092 new FieldDefinition("UpperRangeIntegerValue", FieldType.SIGNED_INTEGER, false, null, null), 093 new FieldDefinition("UpperLimitIntegerValue", FieldType.SIGNED_INTEGER, false, null, null), 094 new FieldDefinition("LowerLimitIntegerValue", FieldType.SIGNED_INTEGER, false, null, null), 095 new FieldDefinition("LowerRangeIntegerValue", FieldType.SIGNED_INTEGER, false, null, null), 096 new FieldDefinition("UpperRangeLongValue", FieldType.SIGNED_LONG, false, null, null), 097 new FieldDefinition("UpperLimitLongValue", FieldType.SIGNED_LONG, false, null, null), 098 new FieldDefinition("LowerLimitLongValue", FieldType.SIGNED_LONG, false, null, null), 099 new FieldDefinition("LowerRangeLongValue", FieldType.SIGNED_LONG, false, null, null), 100 new FieldDefinition("UnitOfMeasureKindName", FieldType.ENTITY_NAME, false, null, null), 101 new FieldDefinition("UnitOfMeasureTypeName", FieldType.ENTITY_NAME, false, null, null), 102 new FieldDefinition("EntityListItemSequenceName", FieldType.ENTITY_NAME, false, null, null), 103 new FieldDefinition("WorkflowName", FieldType.ENTITY_NAME, false, null, null) 104 ); 105 106 STRING_FORM_FIELD_DEFINITIONS = List.of( 107 new FieldDefinition("CheckContentWebAddress", FieldType.NULL, false, null, null), 108 new FieldDefinition("ValidationPattern", FieldType.REGULAR_EXPRESSION, false, null, null), 109 new FieldDefinition("UpperRangeIntegerValue", FieldType.NULL, false, null, null), 110 new FieldDefinition("UpperLimitIntegerValue", FieldType.NULL, false, null, null), 111 new FieldDefinition("LowerLimitIntegerValue", FieldType.NULL, false, null, null), 112 new FieldDefinition("LowerRangeIntegerValue", FieldType.NULL, false, null, null), 113 new FieldDefinition("UpperRangeLongValue", FieldType.NULL, false, null, null), 114 new FieldDefinition("UpperLimitLongValue", FieldType.NULL, false, null, null), 115 new FieldDefinition("LowerLimitLongValue", FieldType.NULL, false, null, null), 116 new FieldDefinition("LowerRangeLongValue", FieldType.NULL, false, null, null), 117 new FieldDefinition("UnitOfMeasureKindName", FieldType.NULL, false, null, null), 118 new FieldDefinition("UnitOfMeasureTypeName", FieldType.NULL, false, null, null), 119 new FieldDefinition("EntityListItemSequenceName", FieldType.NULL, false, null, null), 120 new FieldDefinition("WorkflowName", FieldType.ENTITY_NAME, false, null, null) 121 ); 122 123 INTEGER_FORM_FIELD_DEFINITIONS = List.of( 124 new FieldDefinition("CheckContentWebAddress", FieldType.NULL, false, null, null), 125 new FieldDefinition("ValidationPattern", FieldType.NULL, false, null, null), 126 new FieldDefinition("UpperRangeIntegerValue", FieldType.SIGNED_INTEGER, false, null, null), 127 new FieldDefinition("UpperLimitIntegerValue", FieldType.SIGNED_INTEGER, false, null, null), 128 new FieldDefinition("LowerLimitIntegerValue", FieldType.SIGNED_INTEGER, false, null, null), 129 new FieldDefinition("LowerRangeIntegerValue", FieldType.SIGNED_INTEGER, false, null, null), 130 new FieldDefinition("UpperRangeLongValue", FieldType.NULL, false, null, null), 131 new FieldDefinition("UpperLimitLongValue", FieldType.NULL, false, null, null), 132 new FieldDefinition("LowerLimitLongValue", FieldType.NULL, false, null, null), 133 new FieldDefinition("LowerRangeLongValue", FieldType.NULL, false, null, null), 134 new FieldDefinition("UnitOfMeasureKindName", FieldType.ENTITY_NAME, false, null, null), 135 new FieldDefinition("UnitOfMeasureTypeName", FieldType.ENTITY_NAME, false, null, null), 136 new FieldDefinition("EntityListItemSequenceName", FieldType.NULL, false, null, null), 137 new FieldDefinition("WorkflowName", FieldType.ENTITY_NAME, false, null, null) 138 ); 139 140 LONG_FORM_FIELD_DEFINITIONS = List.of( 141 new FieldDefinition("CheckContentWebAddress", FieldType.NULL, false, null, null), 142 new FieldDefinition("ValidationPattern", FieldType.NULL, false, null, null), 143 new FieldDefinition("UpperRangeIntegerValue", FieldType.NULL, false, null, null), 144 new FieldDefinition("UpperLimitIntegerValue", FieldType.NULL, false, null, null), 145 new FieldDefinition("LowerLimitIntegerValue", FieldType.NULL, false, null, null), 146 new FieldDefinition("LowerRangeIntegerValue", FieldType.NULL, false, null, null), 147 new FieldDefinition("UpperRangeLongValue", FieldType.SIGNED_LONG, false, null, null), 148 new FieldDefinition("UpperLimitLongValue", FieldType.SIGNED_LONG, false, null, null), 149 new FieldDefinition("LowerLimitLongValue", FieldType.SIGNED_LONG, false, null, null), 150 new FieldDefinition("LowerRangeLongValue", FieldType.SIGNED_LONG, false, null, null), 151 new FieldDefinition("UnitOfMeasureKindName", FieldType.ENTITY_NAME, false, null, null), 152 new FieldDefinition("UnitOfMeasureTypeName", FieldType.ENTITY_NAME, false, null, null), 153 new FieldDefinition("EntityListItemSequenceName", FieldType.NULL, false, null, null), 154 new FieldDefinition("WorkflowName", FieldType.ENTITY_NAME, false, null, null) 155 ); 156 157 LISTITEM_FORM_FIELD_DEFINITIONS = List.of( 158 new FieldDefinition("CheckContentWebAddress", FieldType.NULL, false, null, null), 159 new FieldDefinition("ValidationPattern", FieldType.NULL, false, null, null), 160 new FieldDefinition("UpperRangeIntegerValue", FieldType.NULL, false, null, null), 161 new FieldDefinition("UpperLimitIntegerValue", FieldType.NULL, false, null, null), 162 new FieldDefinition("LowerLimitIntegerValue", FieldType.NULL, false, null, null), 163 new FieldDefinition("LowerRangeIntegerValue", FieldType.NULL, false, null, null), 164 new FieldDefinition("UpperRangeLongValue", FieldType.NULL, false, null, null), 165 new FieldDefinition("UpperLimitLongValue", FieldType.NULL, false, null, null), 166 new FieldDefinition("LowerLimitLongValue", FieldType.NULL, false, null, null), 167 new FieldDefinition("LowerRangeLongValue", FieldType.NULL, false, null, null), 168 new FieldDefinition("UnitOfMeasureKindName", FieldType.NULL, false, null, null), 169 new FieldDefinition("UnitOfMeasureTypeName", FieldType.NULL, false, null, null), 170 new FieldDefinition("EntityListItemSequenceName", FieldType.ENTITY_NAME, false, null, null), 171 new FieldDefinition("WorkflowName", FieldType.ENTITY_NAME, false, null, null) 172 ); 173 174 MULTIPLELISTITEM_FORM_FIELD_DEFINITIONS = List.of( 175 new FieldDefinition("CheckContentWebAddress", FieldType.NULL, false, null, null), 176 new FieldDefinition("ValidationPattern", FieldType.NULL, false, null, null), 177 new FieldDefinition("UpperRangeIntegerValue", FieldType.NULL, false, null, null), 178 new FieldDefinition("UpperLimitIntegerValue", FieldType.NULL, false, null, null), 179 new FieldDefinition("LowerLimitIntegerValue", FieldType.NULL, false, null, null), 180 new FieldDefinition("LowerRangeIntegerValue", FieldType.NULL, false, null, null), 181 new FieldDefinition("UpperRangeLongValue", FieldType.NULL, false, null, null), 182 new FieldDefinition("UpperLimitLongValue", FieldType.NULL, false, null, null), 183 new FieldDefinition("LowerLimitLongValue", FieldType.NULL, false, null, null), 184 new FieldDefinition("LowerRangeLongValue", FieldType.NULL, false, null, null), 185 new FieldDefinition("UnitOfMeasureKindName", FieldType.NULL, false, null, null), 186 new FieldDefinition("UnitOfMeasureTypeName", FieldType.NULL, false, null, null), 187 new FieldDefinition("EntityListItemSequenceName", FieldType.ENTITY_NAME, false, null, null), 188 new FieldDefinition("WorkflowName", FieldType.ENTITY_NAME, false, null, null) 189 ); 190 191 WORKFLOW_FORM_FIELD_DEFINITIONS = List.of( 192 new FieldDefinition("CheckContentWebAddress", FieldType.NULL, false, null, null), 193 new FieldDefinition("ValidationPattern", FieldType.NULL, false, null, null), 194 new FieldDefinition("UpperRangeIntegerValue", FieldType.NULL, false, null, null), 195 new FieldDefinition("UpperLimitIntegerValue", FieldType.NULL, false, null, null), 196 new FieldDefinition("LowerLimitIntegerValue", FieldType.NULL, false, null, null), 197 new FieldDefinition("LowerRangeIntegerValue", FieldType.NULL, false, null, null), 198 new FieldDefinition("UpperRangeLongValue", FieldType.NULL, false, null, null), 199 new FieldDefinition("UpperLimitLongValue", FieldType.NULL, false, null, null), 200 new FieldDefinition("LowerLimitLongValue", FieldType.NULL, false, null, null), 201 new FieldDefinition("LowerRangeLongValue", FieldType.NULL, false, null, null), 202 new FieldDefinition("UnitOfMeasureKindName", FieldType.NULL, false, null, null), 203 new FieldDefinition("UnitOfMeasureTypeName", FieldType.NULL, false, null, null), 204 new FieldDefinition("EntityListItemSequenceName", FieldType.NULL, false, null, null), 205 new FieldDefinition("WorkflowName", FieldType.ENTITY_NAME, true, null, null) 206 ); 207 208 OTHER_FORM_FIELD_DEFINITIONS = List.of( 209 new FieldDefinition("CheckContentWebAddress", FieldType.NULL, false, null, null), 210 new FieldDefinition("ValidationPattern", FieldType.NULL, false, null, null), 211 new FieldDefinition("UpperRangeIntegerValue", FieldType.NULL, false, null, null), 212 new FieldDefinition("UpperLimitIntegerValue", FieldType.NULL, false, null, null), 213 new FieldDefinition("LowerLimitIntegerValue", FieldType.NULL, false, null, null), 214 new FieldDefinition("LowerRangeIntegerValue", FieldType.NULL, false, null, null), 215 new FieldDefinition("UpperRangeLongValue", FieldType.NULL, false, null, null), 216 new FieldDefinition("UpperLimitLongValue", FieldType.NULL, false, null, null), 217 new FieldDefinition("LowerLimitLongValue", FieldType.NULL, false, null, null), 218 new FieldDefinition("LowerRangeLongValue", FieldType.NULL, false, null, null), 219 new FieldDefinition("UnitOfMeasureKindName", FieldType.NULL, false, null, null), 220 new FieldDefinition("UnitOfMeasureTypeName", FieldType.NULL, false, null, null), 221 new FieldDefinition("EntityListItemSequenceName", FieldType.NULL, false, null, null), 222 new FieldDefinition("WorkflowName", FieldType.ENTITY_NAME, false, null, null) 223 ); 224 } 225 226 /** Creates a new instance of CreateEntityAttributeCommand */ 227 public CreateEntityAttributeCommand() { 228 super(COMMAND_SECURITY_DEFINITION, FORM_FIELD_DEFINITIONS, false); 229 } 230 231 public static ValidationResult AdditionalEntityAttributeValidation(EntityAttributeEdit edit, Validator validator, 232 EntityAttributeType entityAttributeType) { 233 return switch(EntityAttributeTypes.valueOf(entityAttributeType.getEntityAttributeTypeName())) { 234 case BLOB -> validator.validate(edit, BLOB_FORM_FIELD_DEFINITIONS); 235 case STRING -> validator.validate(edit, STRING_FORM_FIELD_DEFINITIONS); 236 case INTEGER -> validator.validate(edit, INTEGER_FORM_FIELD_DEFINITIONS); 237 case LONG -> validator.validate(edit, LONG_FORM_FIELD_DEFINITIONS); 238 case LISTITEM -> validator.validate(edit, LISTITEM_FORM_FIELD_DEFINITIONS); 239 case MULTIPLELISTITEM -> validator.validate(edit, MULTIPLELISTITEM_FORM_FIELD_DEFINITIONS); 240 case WORKFLOW -> validator.validate(edit, WORKFLOW_FORM_FIELD_DEFINITIONS); 241 default -> validator.validate(edit, OTHER_FORM_FIELD_DEFINITIONS); 242 }; 243 } 244 245 @Override 246 protected ValidationResult validate() { 247 var validator = new Validator(this); 248 var validationResult = validator.validate(form, FORM_FIELD_DEFINITIONS); 249 250 if(!validationResult.getHasErrors()) { 251 var entityAttributeType = EntityAttributeLogic.getInstance().getEntityAttributeTypeByName(this, form.getEntityAttributeTypeName()); 252 253 if(!hasExecutionErrors()) { 254 validationResult = AdditionalEntityAttributeValidation(form, validator, entityAttributeType); 255 } 256 } 257 258 return validationResult; 259 } 260 261 @Override 262 protected BaseResult execute() { 263 var result = CoreResultFactory.getCreateEntityAttributeResult(); 264 EntityAttribute entityAttribute = null; 265 266 if(!hasExecutionErrors()) { 267 var unitOfMeasureKindName = form.getUnitOfMeasureKindName(); 268 var unitOfMeasureTypeName = form.getUnitOfMeasureTypeName(); 269 var parameterCount = (unitOfMeasureKindName == null ? 0 : 1) + (unitOfMeasureTypeName == null ? 0 : 1); 270 271 if(parameterCount == 0 || parameterCount == 2) { 272 var entityType = EntityTypeLogic.getInstance().getEntityTypeByUniversalSpec(this, form); 273 var entityAttributeTypeName = form.getEntityAttributeTypeName(); 274 var entityAttributeType = EntityAttributeLogic.getInstance().getEntityAttributeTypeByName(this, entityAttributeTypeName); 275 276 if(!hasExecutionErrors()) { 277 var entityListItemSequenceName = entityAttributeTypeName.equals(EntityAttributeTypes.LISTITEM.name()) 278 || entityAttributeTypeName.equals(EntityAttributeTypes.MULTIPLELISTITEM.name()) ? 279 form.getEntityListItemSequenceName() : null; 280 Sequence entityListItemSequence = null; 281 282 if(entityListItemSequenceName != null) { 283 var sequenceType = SequenceTypeLogic.getInstance().getSequenceTypeByName(this, SequenceTypes.ENTITY_LIST_ITEM.name()); 284 285 if(!hasExecutionErrors()) { 286 var sequenceControl = Session.getModelController(SequenceControl.class); 287 288 entityListItemSequence = sequenceControl.getSequenceByName(sequenceType, entityListItemSequenceName); 289 290 if(entityListItemSequence == null) { 291 addExecutionError(ExecutionErrors.UnknownEntityListItemSequenceName.name(), entityListItemSequenceName); 292 } 293 } 294 } 295 296 if(!hasExecutionErrors()) { 297 UnitOfMeasureType unitOfMeasureType = null; 298 299 if(parameterCount == 2) { 300 unitOfMeasureType = UnitOfMeasureTypeLogic.getInstance().getUnitOfMeasureTypeByName(this, unitOfMeasureKindName, unitOfMeasureTypeName); 301 } 302 303 if(!hasExecutionErrors()) { 304 var workflowName = form.getWorkflowName(); 305 Workflow workflow = null; 306 307 if(workflowName != null) { 308 workflow = WorkflowLogic.getInstance().getWorkflowByName(this, workflowName); 309 } 310 311 if(!hasExecutionErrors()) { 312 var partyPK = getPartyPK(); 313 var entityAttributeName = form.getEntityAttributeName(); 314 var trackRevisions = Boolean.valueOf(form.getTrackRevisions()); 315 var strCheckContentWebAddress = form.getCheckContentWebAddress(); 316 var checkContentWebAddress = strCheckContentWebAddress == null ? null : Boolean.valueOf(strCheckContentWebAddress); 317 var validationPattern = form.getValidationPattern(); 318 var strUpperRangeIntegerValue = form.getUpperRangeIntegerValue(); 319 var upperRangeIntegerValue = strUpperRangeIntegerValue == null ? null : Integer.valueOf(strUpperRangeIntegerValue); 320 var strUpperLimitIntegerValue = form.getUpperLimitIntegerValue(); 321 var upperLimitIntegerValue = strUpperLimitIntegerValue == null ? null : Integer.valueOf(strUpperLimitIntegerValue); 322 var strLowerLimitIntegerValue = form.getLowerLimitIntegerValue(); 323 var lowerLimitIntegerValue = strLowerLimitIntegerValue == null ? null : Integer.valueOf(strLowerLimitIntegerValue); 324 var strLowerRangeIntegerValue = form.getLowerRangeIntegerValue(); 325 var lowerRangeIntegerValue = strLowerRangeIntegerValue == null ? null : Integer.valueOf(strLowerRangeIntegerValue); 326 var strUpperRangeLongValue = form.getUpperRangeLongValue(); 327 var upperRangeLongValue = strUpperRangeLongValue == null ? null : Long.valueOf(strUpperRangeLongValue); 328 var strUpperLimitLongValue = form.getUpperLimitLongValue(); 329 var upperLimitLongValue = strUpperLimitLongValue == null ? null : Long.valueOf(strUpperLimitLongValue); 330 var strLowerLimitLongValue = form.getLowerLimitLongValue(); 331 var lowerLimitLongValue = strLowerLimitLongValue == null ? null : Long.valueOf(strLowerLimitLongValue); 332 var strLowerRangeLongValue = form.getLowerRangeLongValue(); 333 var lowerRangeLongValue = strLowerRangeLongValue == null ? null : Long.valueOf(strLowerRangeLongValue); 334 var sortOrder = Integer.valueOf(form.getSortOrder()); 335 var description = form.getDescription(); 336 337 entityAttribute = EntityAttributeLogic.getInstance().createEntityAttribute(this, entityType, 338 entityAttributeName, entityAttributeType, trackRevisions, checkContentWebAddress, 339 validationPattern, upperRangeIntegerValue, upperLimitIntegerValue, lowerLimitIntegerValue, 340 lowerRangeIntegerValue, upperRangeLongValue, upperLimitLongValue, lowerLimitLongValue, 341 lowerRangeLongValue, entityListItemSequence, unitOfMeasureType, workflow, sortOrder, 342 partyPK, getPreferredLanguage(), description); 343 } 344 } 345 } 346 } 347 } else { 348 addExecutionError(ExecutionErrors.InvalidParameterCount.name()); 349 } 350 } 351 352 if(entityAttribute != null) { 353 var basePK = entityAttribute.getPrimaryKey(); 354 355 result.setEntityAttributeName(entityAttribute.getLastDetail().getEntityAttributeName()); 356 result.setEntityRef(basePK.getEntityRef()); 357 } 358 359 return result; 360 } 361 362}