// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.dq.helper;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.EList;
import org.talend.commons.exception.ExceptionHandler;
import org.talend.core.model.metadata.builder.database.PluginConstant;
import org.talend.cwm.helper.TaggedValueHelper;
import org.talend.cwm.management.i18n.Messages;
import org.talend.dataquality.analysis.Analysis;
import org.talend.dataquality.domain.pattern.Pattern;
import org.talend.dataquality.helpers.IndicatorCategoryHelper;
import org.talend.dataquality.helpers.MetadataHelper;
import org.talend.dataquality.indicators.Indicator;
import org.talend.dataquality.indicators.definition.IndicatorCategory;
import org.talend.dataquality.indicators.definition.IndicatorDefinition;
import org.talend.dataquality.indicators.definition.userdefine.UDIndicatorDefinition;
import org.talend.dataquality.indicators.definition.userdefine.UserdefineFactory;
import org.talend.dataquality.indicators.sql.UserDefIndicator;
import org.talend.dataquality.indicators.sql.util.IndicatorSqlSwitch;
import org.talend.dq.dbms.DbmsLanguage;
import org.talend.dq.helper.resourcehelper.IndicatorResourceFileHelper;
import org.talend.dq.indicators.definitions.DefinitionHandler;
import org.talend.resource.EResourceConstant;
import org.talend.resource.ResourceManager;
import org.talend.utils.classloader.TalendURLClassLoader;
import org.talend.utils.sugars.ReturnCode;
import orgomg.cwm.objectmodel.core.Expression;
import orgomg.cwm.objectmodel.core.ModelElement;
import orgomg.cwm.objectmodel.core.TaggedValue;
/**
* DOC xqliu class global comment. Detailled comment
*/
public final class UDIHelper {
private static final Map<Indicator, Indicator> JAVAUDIMAP = new HashMap<Indicator, Indicator>();
private static Properties UDI_TEMPLATES_PROPERTIES = new Properties();
public static final String JAREXTENSIONG = "jar";//$NON-NLS-1$
/**
* separate the key from value.
*/
public static final String PARA_SEPARATE_1 = "__PARA_SEP_1__"; //$NON-NLS-1$
/**
* the display name of PARA_SEPARATE_1.
*/
public static final String PARA_SEPARATE_1_DISPLAY = ":"; //$NON-NLS-1$
/**
* separate the KeyValue from another one.
*/
public static final String PARA_SEPARATE_2 = "__PARA_SEP_2__"; //$NON-NLS-1$
/**
* the display name of PARA_SEPARATE_2.
*/
public static final String PARA_SEPARATE_2_DISPLAY = ";"; //$NON-NLS-1$
private static IndicatorSqlSwitch<UserDefIndicator> userDefIndSwitch = new IndicatorSqlSwitch<UserDefIndicator>() {
@Override
public UserDefIndicator caseUserDefIndicator(UserDefIndicator object) {
return object;
}
};
private UDIHelper() {
}
private static Logger log = Logger.getLogger(UDIHelper.class);
// ("select * from *").length
public static final int MIN_EXPRESSION_LENGTH = 16;
public static IndicatorCategory getUDICategory(IndicatorDefinition indicatorDefinition) {
if (indicatorDefinition != null) {
EList<IndicatorCategory> categories = indicatorDefinition.getCategories();
if (categories != null && categories.size() > 0) {
return categories.get(0);
}
}
return null;
}
/**
* getUDICategory by modelElement
*/
public static IndicatorCategory getUDICategory(ModelElement modelElement) {
if (modelElement != null && modelElement instanceof IndicatorDefinition) {
return getUDICategory((IndicatorDefinition) modelElement);
}
return null;
}
public static IndicatorCategory getUDICategory(Indicator indicator) {
if (indicator != null) {
return getUDICategory(indicator.getIndicatorDefinition());
}
return null;
}
/**
* Set the category of the IndicatorDefinition, if the category is null set UserDefinedCount category.
*
* @param definition
* @param category
*/
public static void setUDICategory(IndicatorDefinition definition, IndicatorCategory category) {
if (definition != null) {
if (category == null) {
category = DefinitionHandler.getInstance().getUserDefinedCountIndicatorCategory();
}
EList<IndicatorCategory> categories = definition.getCategories();
if (categories != null) {
categories.clear();
categories.add(category);
}
}
}
public static void setUDICategory(IndicatorDefinition indicatorDefinition, String categoryLabel) {
setUDICategory(indicatorDefinition, DefinitionHandler.getInstance().getIndicatorCategoryByLabel(categoryLabel));
}
public static void setUDICategory(Indicator indicator, String categoryLabel) {
if (indicator != null) {
setUDICategory(indicator.getIndicatorDefinition(), categoryLabel);
}
}
public static UDIndicatorDefinition createUDI(String name, String author, String description, String purpose, String status,
String category, String javaClassName, String javaJarPath) {
// IndicatorDefinition id = DefinitionFactory.eINSTANCE.createIndicatorDefinition();
UDIndicatorDefinition id = UserdefineFactory.eINSTANCE.createUDIndicatorDefinition();
id.setName(name);
MetadataHelper.setAuthor(id, author == null ? PluginConstant.EMPTY_STRING : author);
MetadataHelper.setDescription(description == null ? PluginConstant.EMPTY_STRING : description, id);
MetadataHelper.setPurpose(purpose == null ? PluginConstant.EMPTY_STRING : purpose, id);
// MOD mzhao feature 7479 2009-10-16
MetadataHelper.setDevStatus(id, status == null ? PluginConstant.EMPTY_STRING : status);
TaggedValueHelper.setTaggedValue(id, TaggedValueHelper.CLASS_NAME_TEXT, javaClassName);
TaggedValueHelper.setTaggedValue(id, TaggedValueHelper.JAR_FILE_PATH, javaJarPath);
setUDICategory(id, category);
return id;
}
public static Set<String> getAllIndicatorNames(IFolder folder) {
Set<String> list = new HashSet<String>();
return getNestFolderIndicatorNames(list, folder);
}
private static Set<String> getNestFolderIndicatorNames(Set<String> list, IFolder folder) {
try {
for (IResource resource : folder.members()) {
if (resource instanceof IFile) {
IndicatorDefinition id = IndicatorResourceFileHelper.getInstance().findIndDefinition((IFile) resource);
if (id != null) {
list.add(id.getName());
}
} else {
getNestFolderIndicatorNames(list, (IFolder) resource);
}
}
} catch (CoreException e) {
log.error(e, e);
}
return list;
}
public static String getMatchingIndicatorName(IndicatorDefinition indicatorDefinition, Pattern pattern) {
if (indicatorDefinition != null) {
return pattern.getName() + "(" + indicatorDefinition.getName() + ")";//$NON-NLS-1$//$NON-NLS-2$
} else {
return pattern.getName();
}
}
public static boolean isCount(Indicator indicator) {
return isCategory(indicator, DefinitionHandler.getInstance().getUserDefinedCountIndicatorCategory());
}
public static boolean isCount(IndicatorDefinition indicatorDefinition) {
return isCategory(indicatorDefinition, DefinitionHandler.getInstance().getUserDefinedCountIndicatorCategory());
}
public static boolean isRealValue(Indicator indicator) {
return isCategory(indicator, DefinitionHandler.getInstance().getUserDefinedRealValueIndicatorCategory());
}
public static boolean isRealValue(IndicatorDefinition indicatorDefinition) {
return isCategory(indicatorDefinition, DefinitionHandler.getInstance().getUserDefinedRealValueIndicatorCategory());
}
public static boolean isFrequency(Indicator indicator) {
return isCategory(indicator, DefinitionHandler.getInstance().getUserDefinedFrequencyIndicatorCategory());
}
public static boolean isFrequency(IndicatorDefinition indicatorDefinition) {
return isCategory(indicatorDefinition, DefinitionHandler.getInstance().getUserDefinedFrequencyIndicatorCategory());
}
public static boolean isMatching(Indicator indicator) {
return isCategory(indicator, DefinitionHandler.getInstance().getUserDefinedMatchIndicatorCategory());
}
public static boolean isMatching(IndicatorDefinition indicatorDefinition) {
return isCategory(indicatorDefinition, DefinitionHandler.getInstance().getUserDefinedMatchIndicatorCategory());
}
public static boolean isCategory(Indicator indicator, IndicatorCategory indicatorCategory) {
if (indicator != null) {
return isCategory(indicator.getIndicatorDefinition(), indicatorCategory);
}
return false;
}
public static boolean isCategory(IndicatorDefinition indicatorDefinition, IndicatorCategory indicatorCategory) {
if (indicatorDefinition != null && indicatorCategory != null) {
return indicatorCategory.equals(getUDICategory(indicatorDefinition));
}
return false;
}
public static boolean isUDI(Indicator indicator) {
return indicator instanceof UserDefIndicator;
}
/**
* yyi 2009-09-22 To check the expression is null, empty or less than 16 characters Feature : 8866.
*/
public static boolean isUDIValid(IndicatorDefinition indicatorDefinition) {
boolean valid = true;
if ("".equals(indicatorDefinition.getName())) { //$NON-NLS-1$
valid = false;
}
if ('\'' == indicatorDefinition.getName().charAt(0)) {
valid = false;
}
if (!isJUDIValid(indicatorDefinition)) {
if (0 == indicatorDefinition.getSqlGenericExpression().size() && !isJUDIValid(indicatorDefinition)) {
valid = false;
}
for (Expression exp : indicatorDefinition.getSqlGenericExpression()) {
if (null == exp.getBody() || exp.getBody().length() + 1 < MIN_EXPRESSION_LENGTH) {
valid = false;
}
}
}
return valid;
}
/**
* if the config information if valid for Java Engine return true, else return false.
*
* @param indicatorDefinition
* @return
*/
public static boolean isJUDIValid(IndicatorDefinition indicatorDefinition) {
if (indicatorDefinition == null) {
return false;
}
boolean valid = true;
String classNameText = TaggedValueHelper.getClassNameText(indicatorDefinition);
String jarFilePath = TaggedValueHelper.getJarFilePath(indicatorDefinition);
if (StringUtils.isBlank(classNameText) || StringUtils.isBlank(jarFilePath)) {
valid = false;
}
return valid;
}
public static ReturnCode validate(IndicatorDefinition indicatorDefinition) {
ReturnCode rc = new ReturnCode(true);
List<String> errorList = new ArrayList<String>();
// MOD mzhao feature 11128, In case of Java UDI, No expression is allowed to be saved.
if (!containsJavaUDI(indicatorDefinition)) {
if (0 == indicatorDefinition.getSqlGenericExpression().size()) {
errorList.add(Messages.getString("UDIHelper.validateNoExpression"));//$NON-NLS-1$
rc.setOk(false);
}
}
if (PluginConstant.EMPTY_STRING.equals(indicatorDefinition.getName())) {
errorList.add(Messages.getString("UDIHelper.validateNoName"));//$NON-NLS-1$
rc.setOk(false);
}
for (Expression exp : indicatorDefinition.getSqlGenericExpression()) {
if (null == exp.getBody() || exp.getBody().length() + 1 < MIN_EXPRESSION_LENGTH) {
errorList.add(Messages.getString("UDIHelper.validateTooShort"));//$NON-NLS-1$
rc.setOk(false);
}
}
String message = Messages.getString("UDIHelper.validateCannotSave");//$NON-NLS-1$
String wrap = System.getProperty("line.separator");//$NON-NLS-1$
for (int i = 0; i < errorList.size(); i++) {
message += wrap + (i + 1) + org.talend.dataquality.PluginConstant.DOT_STRING + errorList.get(i);
}
rc.setMessage(message);
return rc;
}
/**
*
* DOC mzhao feature 11128, If the execute engine and by the same time Java User Defined Indicator is also defined,
* then compute via Java UDI, here convert common udi to a Java UDI.
*
* @param udi
* @return
* @throws Exception
*/
public static Indicator adaptToJavaUDI(Indicator indicator) throws Throwable {
Indicator returnIndicator = getUDIFromMap(indicator);
if (returnIndicator != null) {
return returnIndicator;
}
UserDefIndicator adaptedUDI = null;
if (userDefIndSwitch.doSwitch(indicator) != null) {
EList<TaggedValue> taggedValues = indicator.getIndicatorDefinition().getTaggedValue();
String userJavaClassName = null;
String jarPath = null;
for (TaggedValue tv : taggedValues) {
if (tv.getTag().equals(TaggedValueHelper.CLASS_NAME_TEXT)) {
userJavaClassName = tv.getValue();
continue;
}
if (tv.getTag().equals(TaggedValueHelper.JAR_FILE_PATH)) {
jarPath = tv.getValue();
}
}
// MOD by zshen for feature 18724
if (validateJavaUDI(userJavaClassName, jarPath)) {
List<URL> jarUrls = new ArrayList<URL>();
for (File file : getContainJarFile(jarPath)) {
jarUrls.add(file.toURI().toURL());
}
TalendURLClassLoader cl;
// Note that the 2nd parameter (classloader) is needed to load class UserDefinitionIndicator from
// org.talend.dataquality plugin.
cl = new TalendURLClassLoader(jarUrls.toArray(new URL[jarUrls.size()]), UDIHelper.class.getClassLoader());
Class<?> clazz = null;
clazz = cl.findClass(userJavaClassName);
if (clazz != null) {
// MOD yyin 20121012 TDQ-6259
UserDefIndicator judi = (UserDefIndicator) clazz.newInstance();
// judi.setIndicatorDefinition(indicator.getIndicatorDefinition());
PropertyUtils.copyProperties(judi, indicator);
// judi.setAnalyzedElement(indicator.getAnalyzedElement());
adaptedUDI = judi;
JAVAUDIMAP.put(indicator, adaptedUDI);
}
}
}
return adaptedUDI;
}
/**
* DOC zshen Comment method "getUDIFromMap".
*
* @param indicator
*/
private static Indicator getUDIFromMap(Indicator indicator) {
// If the JUDI already been initiatated
if (JAVAUDIMAP.get(indicator) != null) {
return JAVAUDIMAP.get(indicator);
}
// indicator itself already be a java user define indicator.
if (JAVAUDIMAP.values().contains(indicator)) {
return indicator;
}
return null;
}
private static boolean validateJavaUDI(String className, String jarPath) {
if (className == null || jarPath == null || className.trim().equals(PluginConstant.EMPTY_STRING)
|| jarPath.trim().equals(PluginConstant.EMPTY_STRING)) {
return false;
}
return true;
}
public static boolean containsJavaUDI(IndicatorDefinition definition) {
EList<TaggedValue> tvs = definition.getTaggedValue();
int findCount = 0;
for (TaggedValue tv : tvs) {
if (tv.getTag().equals(TaggedValueHelper.CLASS_NAME_TEXT)) {
findCount++;
} else if (tv.getTag().equals(TaggedValueHelper.JAR_FILE_PATH)) {
findCount++;
}
if (findCount == 2) {
return true;
}
}
return false;
}
/**
* DOC klliu Comment method "isJavaUDI".
*
* @param indicator
* @return
*/
public static boolean isJavaUDI(Indicator indicator) {
IndicatorDefinition definition = indicator.getIndicatorDefinition();
if (definition == null) {
return false;
}
return containsJavaUDI(definition);
}
/**
*
* zshen Comment method "getLibJarFileList".
*
* @return
*/
private static List<File> getLibJarFileList() {
List<File> fileList = new ArrayList<File>();
try {
File newFile = ResourceManager.getUDIJarFolder().getLocation().toFile();
if (!newFile.exists()) {
newFile.mkdir();
}
for (org.eclipse.core.resources.IResource fileResource : ResourceManager.getUDIJarFolder().members()) {
if (IResource.FILE == fileResource.getType()
&& JAREXTENSIONG.equalsIgnoreCase(fileResource.getFullPath().getFileExtension())) {
fileList.add(fileResource.getLocation().toFile());
}
}
} catch (CoreException e) {
log.error(e, e);
}
return fileList;
}
private static List<File> getLibJarFileListForJobs() {
List<File> fileList = new ArrayList<File>();
String tdqLibPath = DefinitionHandler.getInstance().getTdqLibPath();
String libJarPath = tdqLibPath + "Indicators" + File.separator + "User Defined Indicators" + File.separator + "lib"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
File newFile = new File(libJarPath);
if (newFile.exists() && newFile.isDirectory()) {
for (File libFile : newFile.listFiles()) {
if (libFile.getName().endsWith(".jar")) { //$NON-NLS-1$
fileList.add(libFile);
}
}
}
return fileList;
}
/**
* Judge whether current folder is udi jar folder
*
* @param folder
* @return true if it is else false
*/
public static boolean isUDILibFolder(IFolder folder) {
return folder.getName().equals(EResourceConstant.USER_DEFINED_INDICATORS_LIB.getName())
&& folder.getFullPath().segmentCount() > 2
&& folder.getFullPath().segment(folder.getFullPath().segmentCount() - 2)
.equals(EResourceConstant.USER_DEFINED_INDICATORS.getName());
}
/**
*
* zshen Comment method "getContainJarFile".
*
* @param jarPathStr
* @return
*/
private static List<File> getContainJarFile(String jarPathStr) {
List<File> fileList = new ArrayList<File>();
List<File> libJarFileList = null;
if (Platform.isRunning()) {
libJarFileList = getLibJarFileList();
} else {
libJarFileList = getLibJarFileListForJobs();
}
for (String containJarName : jarPathStr.split("\\|\\|")) {//$NON-NLS-1$
for (File libJarFile : libJarFileList) {
if (libJarFile.getName().equalsIgnoreCase(containJarName)) {
fileList.add(libJarFile);
break;
}
}
}
return fileList;
}
/**
* Create Templates Properties..
*
* @return
*/
public static Properties getCreateTemplatesProperties() {
InputStream in = UDIHelper.class.getClassLoader().getResourceAsStream("viewRowsTemplates.txt"); //$NON-NLS-1$
try {
UDI_TEMPLATES_PROPERTIES.load(in);
} catch (IOException e) {
log.error(e.getMessage());
}
return UDI_TEMPLATES_PROPERTIES;
}
/**
* get Templates Properties which content is used only by use define indicators.
*
* @return
*/
public static Properties getUDITemplatesProperties() {
if (UDI_TEMPLATES_PROPERTIES != null && !UDI_TEMPLATES_PROPERTIES.isEmpty()) {
return UDI_TEMPLATES_PROPERTIES;
}
return getCreateTemplatesProperties();
}
/**
* get Query From Templates.
*
* @param selectTabNumber
* @param language
* @param category
* @return
*/
public static String getQueryFromTemplates(int selectTabNumber, String language, IndicatorCategory category) {
Properties properties = UDIHelper.getUDITemplatesProperties();
// get sql template depend on the language and selectTabNumber
String key = PluginConstant.EMPTY_STRING;
String autoGenSql = PluginConstant.EMPTY_STRING;
// when from tab0 change to tab1, get full sql
if (selectTabNumber == 1) {
if (IndicatorCategoryHelper.isUserDefCount(category)) {
key = "SqlTemplate." + language + ".UDI.Count"; //$NON-NLS-1$ //$NON-NLS-2$
} else if (IndicatorCategoryHelper.isUserDefRealValue(category)) {
key = "SqlTemplate." + language + ".UDI.RealValue"; //$NON-NLS-1$ //$NON-NLS-2$
} else if (IndicatorCategoryHelper.isUserDefFrequency(category)) {
key = "SqlTemplate." + language + ".UDI.Frequency"; //$NON-NLS-1$ //$NON-NLS-2$
} else if (IndicatorCategoryHelper.isUserDefMatching(category)) {
key = "SqlTemplate." + language + ".UDI.Match"; //$NON-NLS-1$ //$NON-NLS-2$
}
} else if (selectTabNumber == 2) {
// for match is View Valid Rows template
// for others is view rows template
if (IndicatorCategoryHelper.isUserDefMatching(category)) {
key = "SqlTemplate." + language + ".UDI.Match.ViewValidRows"; //$NON-NLS-1$ //$NON-NLS-2$
} else if (IndicatorCategoryHelper.isUserDefRealValue(category)) {
key = "SqlTemplate." + language + ".UDI.RealValue.ViewRows"; //$NON-NLS-1$ //$NON-NLS-2$
} else if (IndicatorCategoryHelper.isUserDefFrequency(category)) {
key = "SqlTemplate." + language + ".UDI.Frequency.ViewRows"; //$NON-NLS-1$ //$NON-NLS-2$
} else if (IndicatorCategoryHelper.isUserDefCount(category)) {
key = "SqlTemplate." + language + ".UDI.Count.ViewRows"; //$NON-NLS-1$ //$NON-NLS-2$
}
} else if (selectTabNumber == 3) {
// for match is View Invalid Rows Template
key = "SqlTemplate." + language + ".UDI.Match.ViewInvalidRows"; //$NON-NLS-1$ //$NON-NLS-2$
} else if (selectTabNumber == 4) {
// for match is View Valid Values Template
key = "SqlTemplate." + language + ".UDI.Match.ViewValidValues"; //$NON-NLS-1$ //$NON-NLS-2$
} else if (selectTabNumber == 5) {
// for match is View Invalid Values Template
key = "SqlTemplate." + language + ".UDI.Match.ViewInvalidValues"; //$NON-NLS-1$ //$NON-NLS-2$
}
key = key.replaceAll(" ", "_"); //$NON-NLS-1$ //$NON-NLS-2$
autoGenSql = properties.getProperty(key);
if (autoGenSql == null) {
if (StringUtils.equalsIgnoreCase(DbmsLanguage.SQL, language)) {
log.error(Messages.getString("UDIHelper.NO_DEFAULT_SQL_EXPR_DEFINED")); //$NON-NLS-1$
return org.talend.dataquality.PluginConstant.EMPTY_STRING;
}
// use default SQL expression if the auto generated SQL cannot be find by given language.
autoGenSql = getQueryFromTemplates(selectTabNumber, DbmsLanguage.SQL, category);
}
return autoGenSql;
}
/**
* check all the indicators, convert common udi to a Java UDI if needed.
*
* @param analysis
*/
public static void updateJUDIsForAnalysis(Analysis analysis) {
EList<Indicator> allIndics = analysis.getResults().getIndicators();
List<Indicator> updatedIndWithJUDI = new ArrayList<Indicator>();
for (Indicator indicator : allIndics) {
// MOD TDQ-8177 sizhaoliu update only the UDIs
if (UDIHelper.isUDI(indicator) && UDIHelper.needUpdateJUDI(indicator)) {
try {
indicator = UDIHelper.adaptToJavaUDI(indicator);
} catch (Throwable e) {
ExceptionHandler.process(e);
}
}
updatedIndWithJUDI.add(indicator);
}
allIndics.clear();
allIndics.addAll(updatedIndWithJUDI);
}
/**
*
* If oldUDI == null mean that jar is changed so need to update
*
* @param udi
* @return
*/
public static boolean needUpdateJUDI(Indicator udi) {
if (UDIHelper.isJUDIValid(udi.getIndicatorDefinition())) {
Indicator oldUDI = UDIHelper.getUDIFromMap(udi);
if (oldUDI == null) {
return true;
}
}
return false;
}
/**
*
* clear special element from JAVAUDIMAP
*
* @param indDef
*/
public static void clearJAVAUDIMAPByIndicatorDefinition(IndicatorDefinition indDef) {
if (indDef == null || !isJUDIValid(indDef)) {
return;
}
for (Indicator indicator : JAVAUDIMAP.keySet()) {
if (indDef.equals(indicator.getIndicatorDefinition())
|| indDef.equals(JAVAUDIMAP.get(indicator).getIndicatorDefinition())) {
// if the jar used by UDI is changed need to set null then adaptToJavaUDI() will reload again
JAVAUDIMAP.put(indicator, null);
}
}
}
public static void clearJAVAUDIMAP() {
JAVAUDIMAP.clear();
}
}