Ejemplo n.º 1
0
  public void fromString(String iRecordId) {
    if (iRecordId != null) iRecordId = iRecordId.trim();

    if (iRecordId == null || iRecordId.isEmpty()) {
      clusterId = CLUSTER_ID_INVALID;
      clusterPosition = CLUSTER_POS_INVALID;
      return;
    }

    if (!OStringSerializerHelper.contains(iRecordId, SEPARATOR))
      throw new IllegalArgumentException(
          "Argument '"
              + iRecordId
              + "' is not a RecordId in form of string. Format must be: <cluster-id>:<cluster-position>");

    final List<String> parts = OStringSerializerHelper.split(iRecordId, SEPARATOR, PREFIX);

    if (parts.size() != 2)
      throw new IllegalArgumentException(
          "Argument received '"
              + iRecordId
              + "' is not a RecordId in form of string. Format must be: #<cluster-id>:<cluster-position>. Example: #3:12");

    clusterId = Integer.parseInt(parts.get(0));
    checkClusterLimits();
    clusterPosition = OClusterPositionFactory.INSTANCE.valueOf(parts.get(1));
  }
  @Override
  public Object execute(
      Object iThis,
      OIdentifiable iCurrentRecord,
      OCommandContext iContext,
      Object ioResult,
      Object[] iMethodParams) {

    if (ioResult != null) {
      final Normalizer.Form form =
          iMethodParams != null && iMethodParams.length > 0
              ? Normalizer.Form.valueOf(
                  OStringSerializerHelper.getStringContent(iMethodParams[0].toString()))
              : Normalizer.Form.NFD;

      String normalized = Normalizer.normalize(ioResult.toString(), form);
      if (iMethodParams != null && iMethodParams.length > 1) {
        normalized =
            normalized.replaceAll(
                OStringSerializerHelper.getStringContent(iMethodParams[0].toString()), "");
      } else {
        normalized = normalized.replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
      }
      ioResult = normalized;
    }
    return ioResult;
  }
Ejemplo n.º 3
0
  protected void parseValues() {
    final int beginFields = parserGetCurrentPosition();

    final int endFields = parserText.indexOf(')', beginFields + 1);
    if (endFields == -1) throwSyntaxErrorException("Missed closed brace");

    final ArrayList<String> fieldNames = new ArrayList<String>();
    parserSetCurrentPosition(
        OStringSerializerHelper.getParameters(parserText, beginFields, endFields, fieldNames));
    if (fieldNames.size() == 0)
      throwSyntaxErrorException("Set of fields is empty. Example: (name, surname)");

    // REMOVE QUOTATION MARKS IF ANY
    for (int i = 0; i < fieldNames.size(); ++i)
      fieldNames.set(i, OStringSerializerHelper.removeQuotationMarks(fieldNames.get(i)));

    parserRequiredKeyword(KEYWORD_VALUES);
    parserSkipWhiteSpaces();
    if (parserIsEnded() || parserText.charAt(parserGetCurrentPosition()) != '(') {
      throwParsingException("Set of values is missed. Example: ('Bill', 'Stuart', 300)");
    }

    int blockStart = parserGetCurrentPosition();
    int blockEnd = parserGetCurrentPosition();

    final List<String> records =
        OStringSerializerHelper.smartSplit(
            parserText, new char[] {','}, blockStart, -1, true, true, false);
    for (String record : records) {

      final List<String> values = new ArrayList<String>();
      blockEnd += OStringSerializerHelper.getParameters(record, 0, -1, values);

      if (blockEnd == -1)
        throw new OCommandSQLParsingException(
            "Missed closed brace. Use " + getSyntax(), parserText, blockStart);

      if (values.isEmpty())
        throw new OCommandSQLParsingException(
            "Set of values is empty. Example: ('Bill', 'Stuart', 300). Use " + getSyntax(),
            parserText,
            blockStart);

      if (values.size() != fieldNames.size())
        throw new OCommandSQLParsingException(
            "Fields not match with values", parserText, blockStart);

      // TRANSFORM FIELD VALUES
      final Map<String, Object> fields = new LinkedHashMap<String, Object>();
      for (int i = 0; i < values.size(); ++i)
        fields.put(
            fieldNames.get(i),
            OSQLHelper.parseValue(
                this, OStringSerializerHelper.decode(values.get(i).trim()), context));

      newRecords.add(fields);
      blockStart = blockEnd;
    }
  }
 /**
  * Register all the names for the same instance.
  *
  * @param iServerCommandInstance
  */
 public void registerCommand(final OServerCommand iServerCommandInstance) {
   for (String name : iServerCommandInstance.getNames())
     if (OStringSerializerHelper.contains(name, '{')) {
       restCommands.put(name, iServerCommandInstance);
     } else if (OStringSerializerHelper.contains(name, '*'))
       wildcardCommands.put(name, iServerCommandInstance);
     else exactCommands.put(name, iServerCommandInstance);
   iServerCommandInstance.configure(server);
 }
  public static Object simpleValueFromStream(final Object iValue, final OType iType) {
    switch (iType) {
      case STRING:
        if (iValue instanceof String) {
          final String s = OStringSerializerHelper.getStringContent(iValue);
          return OStringSerializerHelper.decode(s);
        }
        return iValue.toString();

      case INTEGER:
        if (iValue instanceof Integer) return iValue;
        return new Integer(iValue.toString());

      case BOOLEAN:
        if (iValue instanceof Boolean) return iValue;
        return new Boolean(iValue.toString());

      case FLOAT:
        if (iValue instanceof Float) return iValue;
        return convertValue((String) iValue, iType);

      case DECIMAL:
        if (iValue instanceof BigDecimal) return iValue;
        return convertValue((String) iValue, iType);

      case LONG:
        if (iValue instanceof Long) return iValue;
        return convertValue((String) iValue, iType);

      case DOUBLE:
        if (iValue instanceof Double) return iValue;
        return convertValue((String) iValue, iType);

      case SHORT:
        if (iValue instanceof Short) return iValue;
        return convertValue((String) iValue, iType);

      case BYTE:
        if (iValue instanceof Byte) return iValue;
        return convertValue((String) iValue, iType);

      case BINARY:
        return OStringSerializerHelper.getBinaryContent(iValue);

      case DATE:
      case DATETIME:
        if (iValue instanceof Date) return iValue;
        return convertValue((String) iValue, iType);

      case LINK:
        if (iValue instanceof ORID) return iValue.toString();
        else if (iValue instanceof String) return new ORecordId((String) iValue);
        else return ((ORecord<?>) iValue).getIdentity().toString();
    }

    throw new IllegalArgumentException("Type " + iType + " is not simple type.");
  }
Ejemplo n.º 6
0
  public static void checkFetchPlanValid(final String iFetchPlan) {

    if (iFetchPlan != null && !iFetchPlan.isEmpty()) {
      // CHECK IF THERE IS SOME FETCH-DEPTH
      final List<String> planParts = OStringSerializerHelper.split(iFetchPlan, ' ');
      if (!planParts.isEmpty()) {
        for (String planPart : planParts) {
          final List<String> parts = OStringSerializerHelper.split(planPart, ':');
          if (parts.size() != 2) {
            throw new IllegalArgumentException("Fetch plan '" + iFetchPlan + "' is invalid");
          }
        }
      } else {
        throw new IllegalArgumentException("Fetch plan '" + iFetchPlan + "' is invalid");
      }
    }
  }
  protected ODatabaseDocumentTx getProfiledDatabaseInstance(final OHttpRequest iRequest)
      throws InterruptedException {
    if (iRequest.authorization == null)
      throw new OSecurityAccessException(iRequest.databaseName, "No user and password received");

    final List<String> parts = OStringSerializerHelper.split(iRequest.authorization, ':');

    return OSharedDocumentDatabase.acquire(iRequest.databaseName, parts.get(0), parts.get(1));
  }
Ejemplo n.º 8
0
  public static boolean isFetchPlanValid(final String iFetchPlan) {

    if (iFetchPlan != null && !iFetchPlan.isEmpty()) {
      // CHECK IF THERE IS SOME FETCH-DEPTH
      final List<String> planParts = OStringSerializerHelper.split(iFetchPlan, ' ');
      if (!planParts.isEmpty()) {
        for (String planPart : planParts) {
          final List<String> parts = OStringSerializerHelper.split(planPart, ':');
          if (parts.size() != 2) {
            return false;
          }
        }
      } else {
        return false;
      }
    }

    return true;
  }
Ejemplo n.º 9
0
  public static Map<String, Integer> buildFetchPlan(final String iFetchPlan) {
    final Map<String, Integer> fetchPlan = new HashMap<String, Integer>();
    fetchPlan.put(ROOT_FETCH, 0);
    if (iFetchPlan != null) {
      // CHECK IF THERE IS SOME FETCH-DEPTH
      final List<String> planParts = OStringSerializerHelper.split(iFetchPlan, ' ');
      if (!planParts.isEmpty()) {

        List<String> parts;
        for (String planPart : planParts) {
          parts = OStringSerializerHelper.split(planPart, ':');
          if (parts.size() != 2)
            throw new IllegalArgumentException("Wrong fetch plan: " + planPart);

          fetchPlan.put(parts.get(0), Integer.parseInt(parts.get(1)));
        }
      }
    }
    return fetchPlan;
  }
Ejemplo n.º 10
0
  public static int[] getPorts(final String iHostPortRange) {
    int[] ports;

    if (OStringSerializerHelper.contains(iHostPortRange, ',')) {
      // MULTIPLE ENUMERATED PORTS
      String[] portValues = iHostPortRange.split(",");
      ports = new int[portValues.length];
      for (int i = 0; i < portValues.length; ++i) ports[i] = Integer.parseInt(portValues[i]);

    } else if (OStringSerializerHelper.contains(iHostPortRange, '-')) {
      // MULTIPLE RANGE PORTS
      String[] limits = iHostPortRange.split("-");
      int lowerLimit = Integer.parseInt(limits[0]);
      int upperLimit = Integer.parseInt(limits[1]);
      ports = new int[upperLimit - lowerLimit + 1];
      for (int i = 0; i < upperLimit - lowerLimit + 1; ++i) ports[i] = lowerLimit + i;

    } else
      // SINGLE PORT SPECIFIED
      ports = new int[] {Integer.parseInt(iHostPortRange)};
    return ports;
  }
  protected void searchInClusters() {
    final ODatabaseDocumentInternal database = getDatabase();

    final Set<Integer> clusterIds = new HashSet<Integer>();
    for (String clusterName : parsedTarget.getTargetClusters().keySet()) {
      if (clusterName == null || clusterName.length() == 0)
        throw new OCommandExecutionException("No cluster or schema class selected in query");

      database.checkSecurity(
          ORule.ResourceGeneric.CLUSTER, ORole.PERMISSION_READ, clusterName.toLowerCase());

      if (Character.isDigit(clusterName.charAt(0))) {
        // GET THE CLUSTER NUMBER
        for (int clusterId : OStringSerializerHelper.splitIntArray(clusterName)) {
          if (clusterId == -1)
            throw new OCommandExecutionException("Cluster '" + clusterName + "' not found");

          clusterIds.add(clusterId);
        }
      } else {
        // GET THE CLUSTER NUMBER BY THE CLASS NAME
        final int clusterId = database.getClusterIdByName(clusterName.toLowerCase());
        if (clusterId == -1)
          throw new OCommandExecutionException("Cluster '" + clusterName + "' not found");

        clusterIds.add(clusterId);
      }
    }

    // CREATE CLUSTER AS ARRAY OF INT
    final int[] clIds = new int[clusterIds.size()];
    int i = 0;
    for (int c : clusterIds) clIds[i++] = c;

    final ORID[] range = getRange();

    target =
        new ORecordIteratorClusters<ORecord>(database, database, clIds)
            .setRange(range[0], range[1]);
  }
Ejemplo n.º 12
0
 public static String getDatabaseNameFromURL(final String name) {
   if (OStringSerializerHelper.contains(name, '/'))
     return name.substring(name.lastIndexOf("/") + 1);
   return name;
 }
  public static void simpleValueToStream(
      final StringBuilder iBuffer, final OType iType, final Object iValue) {
    if (iValue == null || iType == null) return;
    switch (iType) {
      case STRING:
        iBuffer.append('"');
        iBuffer.append(OStringSerializerHelper.encode(iValue.toString()));
        iBuffer.append('"');
        break;

      case BOOLEAN:
        iBuffer.append(String.valueOf(iValue));
        break;

      case INTEGER:
        iBuffer.append(String.valueOf(iValue));
        break;

      case FLOAT:
        iBuffer.append(String.valueOf(iValue));
        iBuffer.append('f');
        break;

      case DECIMAL:
        if (iValue instanceof BigDecimal) iBuffer.append(((BigDecimal) iValue).toPlainString());
        else iBuffer.append(String.valueOf(iValue));
        iBuffer.append('c');
        break;

      case LONG:
        iBuffer.append(String.valueOf(iValue));
        iBuffer.append('l');
        break;

      case DOUBLE:
        iBuffer.append(String.valueOf(iValue));
        iBuffer.append('d');
        break;

      case SHORT:
        iBuffer.append(String.valueOf(iValue));
        iBuffer.append('s');
        break;

      case BYTE:
        if (iValue instanceof Character) iBuffer.append((int) ((Character) iValue).charValue());
        else if (iValue instanceof String)
          iBuffer.append(String.valueOf((int) ((String) iValue).charAt(0)));
        else iBuffer.append(String.valueOf(iValue));
        iBuffer.append('b');
        break;

      case BINARY:
        iBuffer.append(OStringSerializerHelper.BINARY_BEGINEND);
        if (iValue instanceof Byte)
          iBuffer.append(OBase64Utils.encodeBytes(new byte[] {((Byte) iValue).byteValue()}));
        else iBuffer.append(OBase64Utils.encodeBytes((byte[]) iValue));
        iBuffer.append(OStringSerializerHelper.BINARY_BEGINEND);
        break;

      case DATE:
        if (iValue instanceof Date) {
          // RESET HOURS, MINUTES, SECONDS AND MILLISECONDS
          Calendar calendar = Calendar.getInstance();
          calendar.setTime((Date) iValue);
          calendar.set(Calendar.HOUR_OF_DAY, 0);
          calendar.set(Calendar.MINUTE, 0);
          calendar.set(Calendar.SECOND, 0);
          calendar.set(Calendar.MILLISECOND, 0);

          iBuffer.append(calendar.getTimeInMillis());
        } else iBuffer.append(iValue);
        iBuffer.append('a');
        break;

      case DATETIME:
        if (iValue instanceof Date) iBuffer.append(((Date) iValue).getTime());
        else iBuffer.append(iValue);
        iBuffer.append('t');
        break;
    }
  }
  /**
   * Parses a string returning the value with the closer type. Numbers by default are INTEGER if
   * haven't decimal separator, otherwise FLOAT. To treat all the number types numbers are postponed
   * with a character that tells the type: b=byte, s=short, l=long, f=float, d=double, t=date. If
   * starts with # it's a RecordID. Most of the code is equals to getType() but has been copied to
   * speed-up it.
   *
   * @param iUnusualSymbols Localized decimal number separators
   * @param iValue Value to parse
   * @return The closest type recognized
   */
  public static Object getTypeValue(final String iValue) {
    if (iValue == null) return null;

    if (iValue.length() == 0) return "";

    if (iValue.length() > 1)
      if (iValue.charAt(0) == '"' && iValue.charAt(iValue.length() - 1) == '"')
        // STRING
        return OStringSerializerHelper.decode(iValue.substring(1, iValue.length() - 1));
      else if (iValue.charAt(0) == OStringSerializerHelper.BINARY_BEGINEND
          && iValue.charAt(iValue.length() - 1) == OStringSerializerHelper.BINARY_BEGINEND)
        // STRING
        return OStringSerializerHelper.getBinaryContent(iValue);
      else if (iValue.charAt(0) == OStringSerializerHelper.COLLECTION_BEGIN
          && iValue.charAt(iValue.length() - 1) == OStringSerializerHelper.COLLECTION_END) {
        // COLLECTION
        final ArrayList<String> coll = new ArrayList<String>();
        OStringSerializerHelper.getCollection(iValue, 0, coll);
        return coll;
      } else if (iValue.charAt(0) == OStringSerializerHelper.MAP_BEGIN
          && iValue.charAt(iValue.length() - 1) == OStringSerializerHelper.MAP_END) {
        // MAP
        return OStringSerializerHelper.getMap(iValue);
      }

    if (iValue.charAt(0) == ORID.PREFIX)
      // RID
      return new ORecordId(iValue);

    boolean integer = true;
    char c;

    for (int index = 0; index < iValue.length(); ++index) {
      c = iValue.charAt(index);
      if (c < '0' || c > '9')
        if ((index == 0 && (c == '+' || c == '-'))) continue;
        else if (c == DECIMAL_SEPARATOR) integer = false;
        else {
          if (index > 0) {
            if (!integer && c == 'E') {
              // CHECK FOR SCIENTIFIC NOTATION
              if (index < iValue.length()) index++;
              if (iValue.charAt(index) == '-') continue;
            }

            final String v = iValue.substring(0, index);

            if (c == 'f') return new Float(v);
            else if (c == 'c') return new BigDecimal(v);
            else if (c == 'l') return new Long(v);
            else if (c == 'd') return new Double(v);
            else if (c == 'b') return new Byte(v);
            else if (c == 'a' || c == 't') return new Date(Long.parseLong(v));
            else if (c == 's') return new Short(v);
          }
          return iValue;
        }
    }

    if (integer) {
      try {
        return new Integer(iValue);
      } catch (NumberFormatException e) {
        return new Long(iValue);
      }
    } else return new BigDecimal(iValue);
  }
Ejemplo n.º 15
0
  /**
   * Convert types between numbers based on the iTargetClass parameter.
   *
   * @param iValue Value to convert
   * @param iTargetClass Expected class
   * @return The converted value or the original if no conversion was applied
   */
  @SuppressWarnings({"unchecked", "rawtypes"})
  public static Object convert(final Object iValue, final Class<?> iTargetClass) {
    if (iValue == null) return null;

    if (iValue.getClass().equals(iTargetClass))
      // SAME TYPE: DON'T CONVERT IT
      return iValue;

    if (iTargetClass.isAssignableFrom(iValue.getClass()))
      // COMPATIBLE TYPES: DON'T CONVERT IT
      return iValue;

    try {
      if (iValue instanceof OBinary && iTargetClass.isAssignableFrom(byte[].class))
        return ((OBinary) iValue).toByteArray();
      else if (byte[].class.isAssignableFrom(iTargetClass)) {
        return OStringSerializerHelper.getBinaryContent(iValue);
      } else if (byte[].class.isAssignableFrom(iValue.getClass())) {
        return iValue;
      } else if (iTargetClass.isEnum()) {
        if (iValue instanceof Number)
          return ((Class<Enum>) iTargetClass).getEnumConstants()[((Number) iValue).intValue()];
        return Enum.valueOf((Class<Enum>) iTargetClass, iValue.toString());
      } else if (iTargetClass.equals(Byte.TYPE) || iTargetClass.equals(Byte.class)) {
        if (iValue instanceof Byte) return iValue;
        else if (iValue instanceof String) return Byte.parseByte((String) iValue);
        else return ((Number) iValue).byteValue();

      } else if (iTargetClass.equals(Short.TYPE) || iTargetClass.equals(Short.class)) {
        if (iValue instanceof Short) return iValue;
        else if (iValue instanceof String) return Short.parseShort((String) iValue);
        else return ((Number) iValue).shortValue();

      } else if (iTargetClass.equals(Integer.TYPE) || iTargetClass.equals(Integer.class)) {
        if (iValue instanceof Integer) return iValue;
        else if (iValue instanceof String) return Integer.parseInt((String) iValue);
        else return ((Number) iValue).intValue();

      } else if (iTargetClass.equals(Long.TYPE) || iTargetClass.equals(Long.class)) {
        if (iValue instanceof Long) return iValue;
        else if (iValue instanceof String) return Long.parseLong((String) iValue);
        else return ((Number) iValue).longValue();

      } else if (iTargetClass.equals(Float.TYPE) || iTargetClass.equals(Float.class)) {
        if (iValue instanceof Float) return iValue;
        else if (iValue instanceof String) return Float.parseFloat((String) iValue);
        else return ((Number) iValue).floatValue();

      } else if (iTargetClass.equals(BigDecimal.class)) {
        if (iValue instanceof BigDecimal) return iValue;
        else if (iValue instanceof String) return new BigDecimal((String) iValue);
        else if (iValue instanceof Number) return new BigDecimal(iValue.toString());

      } else if (iTargetClass.equals(Double.TYPE) || iTargetClass.equals(Double.class)) {
        if (iValue instanceof Double) return iValue;
        else if (iValue instanceof String) return Double.parseDouble((String) iValue);
        else return ((Number) iValue).doubleValue();

      } else if (iTargetClass.equals(Boolean.TYPE) || iTargetClass.equals(Boolean.class)) {
        if (iValue instanceof Boolean) return ((Boolean) iValue).booleanValue();
        else if (iValue instanceof String)
          return ((String) iValue).equalsIgnoreCase("true") ? Boolean.TRUE : Boolean.FALSE;
        else if (iValue instanceof Number) return ((Number) iValue).intValue() != 0;

      } else if (iValue instanceof Collection<?> && Set.class.isAssignableFrom(iTargetClass)) {
        final Set<Object> set = new HashSet<Object>();
        set.addAll((Collection<? extends Object>) iValue);
        return set;

      } else if (iTargetClass.equals(Date.class)) {
        if (iValue instanceof Number) return new Date(((Number) iValue).longValue());
        if (iValue instanceof String) {
          try {
            return ODatabaseRecordThreadLocal.INSTANCE
                .get()
                .getStorage()
                .getConfiguration()
                .getDateTimeFormatInstance()
                .parse((String) iValue);
          } catch (ParseException e) {
            return ODatabaseRecordThreadLocal.INSTANCE
                .get()
                .getStorage()
                .getConfiguration()
                .getDateFormatInstance()
                .parse((String) iValue);
          }
        }
      } else if (iTargetClass.equals(String.class)) return iValue.toString();
    } catch (Exception e) {
      OLogManager.instance()
          .debug(
              OType.class, "Error in conversion of value '%s' to type '%s'", iValue, iTargetClass);
      return null;
    }

    return iValue;
  }
Ejemplo n.º 16
0
 public OSQLFilterItemFieldAny(final OSQLFilter iQueryCompiled, final String iName) {
   super(iQueryCompiled, iName, OStringSerializerHelper.getParameters(iName));
 }
  @Override
  public boolean beforeExecute(final OHttpRequest iRequest, OHttpResponse iResponse)
      throws IOException {
    final String[] urlParts = iRequest.url.substring(1).split("/");
    if (urlParts.length < 2)
      throw new OHttpRequestException(
          "Syntax error in URL. Expected is: <command>/<database>[/...]");

    iRequest.databaseName = urlParts[1].replace(DBNAME_DIR_SEPARATOR, '/');
    final List<String> authenticationParts =
        iRequest.authorization != null
            ? OStringSerializerHelper.split(iRequest.authorization, ':')
            : null;

    if (iRequest.sessionId == null || iRequest.sessionId.length() == 1) {
      // NO SESSION
      if (iRequest.authorization == null || SESSIONID_LOGOUT.equals(iRequest.sessionId)) {
        sendAuthorizationRequest(iRequest, iResponse, iRequest.databaseName);
        return false;
      } else return authenticate(iRequest, iResponse, authenticationParts, iRequest.databaseName);

    } else {
      // CHECK THE SESSION VALIDITY
      final OHttpSession currentSession =
          OHttpSessionManager.getInstance().getSession(iRequest.sessionId);
      if (currentSession == null) {
        // SESSION EXPIRED
        sendAuthorizationRequest(iRequest, iResponse, iRequest.databaseName);
        return false;

      } else if (!currentSession.getDatabaseName().equals(iRequest.databaseName)) {

        // SECURITY PROBLEM: CROSS DATABASE REQUEST!
        OLogManager.instance()
            .warn(
                this,
                "Session %s is trying to access to the database '%s', but has been authenticated against the database '%s'",
                iRequest.sessionId,
                iRequest.databaseName,
                currentSession.getDatabaseName());
        sendAuthorizationRequest(iRequest, iResponse, iRequest.databaseName);
        return false;

      } else if (authenticationParts != null
          && !currentSession.getUserName().equals(authenticationParts.get(0))) {

        // SECURITY PROBLEM: CROSS DATABASE REQUEST!
        OLogManager.instance()
            .warn(
                this,
                "Session %s is trying to access to the database '%s' with user '%s', but has been authenticated with user '%s'",
                iRequest.sessionId,
                iRequest.databaseName,
                authenticationParts.get(0),
                currentSession.getUserName());
        sendAuthorizationRequest(iRequest, iResponse, iRequest.databaseName);
        return false;
      }

      return true;
    }
  }