This is an automated email from the ASF dual-hosted git repository. sruehl pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git
The following commit(s) were added to refs/heads/master by this push: new 9c820f7 [ALL] added new PlcInvalidAddress to indicate an invalid address 9c820f7 is described below commit 9c820f7adf8eb39868e5c4b31b6ae5983d404d37 Author: Sebastian Rühl <sru...@apache.org> AuthorDate: Thu Aug 23 11:12:32 2018 +0200 [ALL] added new PlcInvalidAddress to indicate an invalid address --- .../plc4x/java/api/connection/PlcConnection.java | 6 +-- .../java/api/exceptions/PlcInvalidAddress.java | 53 ++++++++++++++++++++++ .../ads/protocol/util/LittleEndianDecoder.java | 37 +++++++-------- .../ads/protocol/util/LittleEndianEncoder.java | 3 +- .../ads/protocol/util/LittleEndianDecoderTest.java | 3 +- .../ads/protocol/util/LittleEndianEncoderTest.java | 4 +- .../plc4x/java/base/connection/MockConnection.java | 3 +- .../java/modbus/netty/Plc4XModbusProtocol.java | 10 ++-- .../plc4x/java/s7/connection/S7PlcConnection.java | 7 ++- .../plc4x/java/s7/netty/util/S7TypeDecoder.java | 19 ++++---- .../plc4x/java/s7/netty/util/S7TypeEncoder.java | 6 +-- .../java/s7/connection/S7PlcConnectionTests.java | 2 +- 12 files changed, 102 insertions(+), 51 deletions(-) diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcConnection.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcConnection.java index 624f409..29d9438 100644 --- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcConnection.java +++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcConnection.java @@ -19,7 +19,7 @@ under the License. package org.apache.plc4x.java.api.connection; import org.apache.plc4x.java.api.exceptions.PlcConnectionException; -import org.apache.plc4x.java.api.exceptions.PlcException; +import org.apache.plc4x.java.api.exceptions.PlcInvalidAddress; import org.apache.plc4x.java.api.model.Address; import java.util.Optional; @@ -60,9 +60,9 @@ public interface PlcConnection extends AutoCloseable { * * @param addressString String representation of an address for the current type of PLC/protocol. * @return Address object identifying an address for the current type of PLC/protocol. - * @throws PlcException an exception if there was a problem parsing the address string. + * @throws PlcInvalidAddress an exception if there was a problem parsing the address string. */ - Address parseAddress(String addressString) throws PlcException; + Address parseAddress(String addressString) throws PlcInvalidAddress; Optional<PlcLister> getLister(); diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcInvalidAddress.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcInvalidAddress.java new file mode 100644 index 0000000..660f701 --- /dev/null +++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcInvalidAddress.java @@ -0,0 +1,53 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.plc4x.java.api.exceptions; + +import java.util.regex.Pattern; + +/** + * Indicates an invalid Address. + */ +public class PlcInvalidAddress extends PlcException { + private static final long serialVersionUID = 1L; + + public PlcInvalidAddress(String addressToBeParsed, Pattern pattern) { + super(addressToBeParsed + " doesn't match " + pattern); + } + + public PlcInvalidAddress(String addressToBeParsed, Pattern pattern, String readablePattern) { + super(addressToBeParsed + " doesn't match " + readablePattern + '(' + pattern + ')'); + } + + public PlcInvalidAddress(String message) { + super(message); + } + + public PlcInvalidAddress(String message, Throwable cause) { + super(message, cause); + } + + public PlcInvalidAddress(Throwable cause) { + super(cause); + } + + public PlcInvalidAddress(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java index 6481952..50f53ce 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java @@ -22,6 +22,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.plc4x.java.ads.api.commands.types.Length; import org.apache.plc4x.java.ads.api.commands.types.TimeStamp; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; +import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException; import java.math.BigInteger; import java.util.*; @@ -56,11 +57,11 @@ public class LittleEndianDecoder { } @SuppressWarnings("unchecked") - public static <T> List<T> decodeData(Class<T> datatype, byte[] adsData) throws PlcProtocolException { - if (datatype == byte[].class) { + public static <T> List<T> decodeData(Class<T> dataType, byte[] adsData) throws PlcProtocolException { + if (dataType == byte[].class) { return (List<T>) Collections.singletonList(adsData); } - if (datatype == Byte[].class) { + if (dataType == Byte[].class) { return (List<T>) Collections.singletonList(ArrayUtils.toObject(adsData)); } List<Object> result = new LinkedList<>(); @@ -69,19 +70,19 @@ public class LittleEndianDecoder { // Expand arrays to avoid IndexOutOfBoundsException final byte[] safeLengthAdsData; - if (datatype == Short.class && length < 2) { + if (dataType == Short.class && length < 2) { safeLengthAdsData = new byte[2]; System.arraycopy(adsData, 0, safeLengthAdsData, 0, length); - } else if (datatype == Integer.class && length < 4) { + } else if (dataType == Integer.class && length < 4) { safeLengthAdsData = new byte[4]; System.arraycopy(adsData, 0, safeLengthAdsData, 0, length); - } else if (datatype == Float.class && length < 4) { + } else if (dataType == Float.class && length < 4) { safeLengthAdsData = new byte[4]; System.arraycopy(adsData, 0, safeLengthAdsData, 0, length); - } else if (datatype == Double.class && length < 8) { + } else if (dataType == Double.class && length < 8) { safeLengthAdsData = new byte[8]; System.arraycopy(adsData, 0, safeLengthAdsData, 0, length); - } else if ((datatype == Calendar.class || Calendar.class.isAssignableFrom(datatype)) && length < 8) { + } else if ((dataType == Calendar.class || Calendar.class.isAssignableFrom(dataType)) && length < 8) { safeLengthAdsData = new byte[8]; System.arraycopy(adsData, 0, safeLengthAdsData, 0, length); } else { @@ -90,35 +91,35 @@ public class LittleEndianDecoder { while (i < length) { byte byteOne = safeLengthAdsData[i]; - if (datatype == String.class) { + if (dataType == String.class) { i = decodeString(safeLengthAdsData, i, length, result); - } else if (datatype == Boolean.class) { + } else if (dataType == Boolean.class) { result.add((byteOne & 0x01) == 0x01); i += 1; - } else if (datatype == Byte.class) { + } else if (dataType == Byte.class) { result.add(byteOne); i += 1; - } else if (datatype == Short.class) { + } else if (dataType == Short.class) { decodeShort(safeLengthAdsData, i, result); i += 2; - } else if (datatype == Integer.class) { + } else if (dataType == Integer.class) { decodeInteger(safeLengthAdsData, i, result); i += 4; - } else if (datatype == BigInteger.class) { + } else if (dataType == BigInteger.class) { decodeBigInteger(safeLengthAdsData, result); // A big integer can consume the whole stream i = length; - } else if (datatype == Float.class) { + } else if (dataType == Float.class) { decodeFloat(safeLengthAdsData, i, result); i += 4; - } else if (datatype == Double.class) { + } else if (dataType == Double.class) { decodeDouble(safeLengthAdsData, i, result); i += 8; - } else if (datatype == Calendar.class || Calendar.class.isAssignableFrom(datatype)) { + } else if (dataType == Calendar.class || Calendar.class.isAssignableFrom(dataType)) { extractCalendar(safeLengthAdsData, i, result); i += 8; } else { - throw new PlcProtocolException("Unsupported datatype " + datatype.getSimpleName()); + throw new PlcUnsupportedDataTypeException(dataType); } } return (List<T>) result; diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java index c477c5f..a66fa0b 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java @@ -22,6 +22,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.plc4x.java.ads.api.commands.types.TimeStamp; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; +import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -68,7 +69,7 @@ public class LittleEndianEncoder { } else if (valueType == Byte[].class) { result = encodeBigByteArray(Arrays.stream(values).map(Byte[].class::cast)); } else { - throw new PlcProtocolException("Unsupported datatype " + valueType); + throw new PlcUnsupportedDataTypeException(valueType); } // TODO: maybe we can replace this by a smarter flatmap diff --git a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoderTest.java b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoderTest.java index 65e7883..12e5841 100644 --- a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoderTest.java +++ b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoderTest.java @@ -20,6 +20,7 @@ package org.apache.plc4x.java.ads.protocol.util; import org.apache.plc4x.java.ads.api.commands.types.Length; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; +import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException; import org.junit.Test; import java.util.Calendar; @@ -79,7 +80,7 @@ public class LittleEndianDecoderTest { assertEquals(asList("plc4x", "plc4x"), LittleEndianDecoder.decodeData(String.class, new byte[]{0x70, 0x6c, 0x63, 0x34, 0x78, 0x0, 0x70, 0x6c, 0x63, 0x34, 0x78, 0x0})); assertThrows(PlcProtocolException.class, () -> LittleEndianDecoder.decodeData(String.class, new byte[]{0x01})); - assertThrows(PlcProtocolException.class, () -> LittleEndianDecoder.decodeData(this.getClass(), new byte[10])); + assertThrows(PlcUnsupportedDataTypeException.class, () -> LittleEndianDecoder.decodeData(this.getClass(), new byte[10])); } } \ No newline at end of file diff --git a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoderTest.java b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoderTest.java index 40f02da..cc08e13 100644 --- a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoderTest.java +++ b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoderTest.java @@ -18,7 +18,7 @@ */ package org.apache.plc4x.java.ads.protocol.util; -import org.apache.plc4x.java.api.exceptions.PlcProtocolException; +import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException; import org.junit.Test; import java.util.Calendar; @@ -56,6 +56,6 @@ public class LittleEndianEncoderTest { assertByteEquals(new byte[]{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00}, LittleEndianEncoder.encodeData(String.class, "HelloWorld!")); assertByteEquals(new byte[]{0x70, 0x6c, 0x63, 0x34, 0x78, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00}, LittleEndianEncoder.encodeData(String.class, "plc4x", "HelloWorld!")); - assertThrows(PlcProtocolException.class, () -> LittleEndianEncoder.encodeData(this.getClass(), "")); + assertThrows(PlcUnsupportedDataTypeException.class, () -> LittleEndianEncoder.encodeData(this.getClass(), "")); } } \ No newline at end of file diff --git a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java index a21d869..a5eae3e 100644 --- a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java +++ b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java @@ -19,7 +19,6 @@ under the License. package org.apache.plc4x.java.base.connection; import io.netty.channel.ChannelHandler; -import org.apache.plc4x.java.api.exceptions.PlcException; import org.apache.plc4x.java.api.model.Address; import java.util.concurrent.CompletableFuture; @@ -40,7 +39,7 @@ public class MockConnection extends AbstractPlcConnection { } @Override - public Address parseAddress(String addressString) throws PlcException { + public Address parseAddress(String addressString) { return null; } diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java index 00ca660..880fa5c 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java @@ -30,7 +30,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.plc4x.java.api.exceptions.PlcException; import org.apache.plc4x.java.api.exceptions.PlcNotImplementedException; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; -import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; +import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException; import org.apache.plc4x.java.api.messages.*; import org.apache.plc4x.java.api.messages.items.*; import org.apache.plc4x.java.api.types.ResponseCode; @@ -311,7 +311,7 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload, } else if (value.getClass() == Double.class) { coilSet = value.equals(1.0d); } else { - throw new PlcRuntimeException("Unsupported datatype detected " + value.getClass()); + throw new PlcUnsupportedDataTypeException(value.getClass()); } byte coilToSet = coilSet ? (byte) 1 : (byte) 0; actualCoil = (byte) (actualCoil & 0xff | coilToSet << i); @@ -404,7 +404,7 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload, } buffer.writeShort((int) Math.round((double) value)); } else { - throw new PlcRuntimeException("Unsupported datatype detected " + value.getClass()); + throw new PlcUnsupportedDataTypeException(value.getClass()); } } byte[] result = new byte[buffer.writerIndex()]; @@ -468,7 +468,7 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload, T itemToBeAdded = (T) Double.valueOf(coilFlag); data.add(itemToBeAdded); } else { - throw new PlcRuntimeException("Unsupported datatype detected " + dataType); + throw new PlcUnsupportedDataTypeException(dataType); } bitIndex++; } @@ -541,7 +541,7 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload, T itemToBeAdded = (T) new Double(intValue); data.add(itemToBeAdded); } else { - throw new PlcRuntimeException("Unsupported datatype detected " + dataType); + throw new PlcUnsupportedDataTypeException(dataType); } } return data; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index a9740d3..febc365 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -25,7 +25,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.plc4x.java.api.connection.PlcReader; import org.apache.plc4x.java.api.connection.PlcWriter; import org.apache.plc4x.java.api.exceptions.PlcConnectionException; -import org.apache.plc4x.java.api.exceptions.PlcException; +import org.apache.plc4x.java.api.exceptions.PlcInvalidAddress; import org.apache.plc4x.java.api.messages.PlcReadRequest; import org.apache.plc4x.java.api.messages.PlcReadResponse; import org.apache.plc4x.java.api.messages.PlcWriteRequest; @@ -249,7 +249,7 @@ public class S7PlcConnection extends AbstractPlcConnection implements PlcReader, @Override - public Address parseAddress(String addressString) throws PlcException { + public Address parseAddress(String addressString) throws PlcInvalidAddress { Matcher datablockAddressMatcher = S7_DATABLOCK_ADDRESS_PATTERN.matcher(addressString); if (datablockAddressMatcher.matches()) { int datablockNumber = Integer.parseInt(datablockAddressMatcher.group("blockNumber")); @@ -258,8 +258,7 @@ public class S7PlcConnection extends AbstractPlcConnection implements PlcReader, } Matcher addressMatcher = S7_ADDRESS_PATTERN.matcher(addressString); if (!addressMatcher.matches()) { - throw new PlcConnectionException( - "Address string doesn't match the format '{area}/{offset}[/{bit-offset}]'"); + throw new PlcInvalidAddress(addressString, S7_ADDRESS_PATTERN, "{area}/{offset}[/{bit-offset}]"); } MemoryArea memoryArea = MemoryArea.valueOf(addressMatcher.group("memoryArea")); int byteOffset = Integer.parseInt(addressMatcher.group("byteOffset")); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeDecoder.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeDecoder.java index 68b85a5..896f506 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeDecoder.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeDecoder.java @@ -19,8 +19,9 @@ package org.apache.plc4x.java.s7.netty.util; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; +import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; @@ -79,20 +80,16 @@ public class S7TypeDecoder { // Every string value had a prefix of two bytes for which I have no idea, what the meaning is. // This code assumes the string values doesn't contain UTF-8 values with a code of 0x00 as it // uses this as termination char. - try { - int j = 0; - for (; j < s7Data.length; j++) { - if (s7Data[j] == 0) { - break; - } + int j = 0; + for (; j < s7Data.length; j++) { + if (s7Data[j] == 0) { + break; } - result.add(new String(s7Data, 2, j - 2, "UTF-8")); - } catch (UnsupportedEncodingException e) { - throw new PlcProtocolException("Error decoding String value", e); } + result.add(new String(s7Data, 2, j - 2, StandardCharsets.UTF_8)); i += s7Data.length; } else { - throw new PlcProtocolException("Unsupported data type " + datatype.getSimpleName()); + throw new PlcUnsupportedDataTypeException(datatype); } } return (List<T>) result; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeEncoder.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeEncoder.java index 4205887..263e6bd 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeEncoder.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeEncoder.java @@ -19,7 +19,7 @@ package org.apache.plc4x.java.s7.netty.util; import org.apache.plc4x.java.api.exceptions.PlcNotImplementedException; -import org.apache.plc4x.java.api.exceptions.PlcProtocolException; +import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException; import java.util.Calendar; @@ -29,7 +29,7 @@ public class S7TypeEncoder { // Utility class } - public static byte[] encodeData(Object[] values) throws PlcProtocolException { + public static byte[] encodeData(Object[] values) { final int length = values.length; if (length == 0) { return new byte[]{}; @@ -54,7 +54,7 @@ public class S7TypeEncoder { } else if (valueType == String.class) { result = encodeString(values, length); } else { - throw new PlcProtocolException("Unsupported data type " + valueType); + throw new PlcUnsupportedDataTypeException(valueType); } return result; } diff --git a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java index f27740a..feab039 100644 --- a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java +++ b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java @@ -67,7 +67,7 @@ public class S7PlcConnectionTests { s7PlcConnection.parseAddress(""); } catch (PlcException exception) { - assertThat(exception.getMessage(), startsWith("Address string doesn't match") ); + assertThat(exception.getMessage(), startsWith(" doesn't match ") ); } }