+++ /dev/null
-/*
- * Copyright (c) 2018-2019. Developed by Hedgecode.
- *
- * Licensed 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.hedgecode.chess;
-
-/**
- * Chess QR Code Main Application.
- *
- * @author Dmitry Samoshin aka gotty
- */
-public final class ChessQRCodeApp {
-
- public static void main(String[] args) {
-
-
- }
-
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018-2019. Developed by Hedgecode.
+ *
+ * Licensed 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.hedgecode.chess.qrcode;
+
+import org.hedgecode.chess.ChessHogConsole;
+
+/**
+ * Chess QR Code Main Application.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class ChessQRCodeApp {
+
+ private static final String[] QRCODE_MODULE_LOGO = {
+ " _ ",
+ " ___ ___ ___ ___ _| |___ ",
+ " | . | _| _| . | . | -_| ",
+ " |_ |_| |___|___|___|___| ",
+ " |_| _ _ ",
+ " _____ ___ _| |_ _| |___ ",
+ " | | . | . | | | | -_| ",
+ " |_|_|_|___|___|___|_|___| ",
+ " "
+ };
+
+ public static void main(String[] args) {
+
+ ChessHogConsole.init();
+
+ for (String line : QRCODE_MODULE_LOGO) {
+ ChessHogConsole.console(line);
+ }
+
+ }
+
+}
\ No newline at end of file
* limitations under the License.
*/
-package org.hedgecode.chess;
+package org.hedgecode.chess.qrcode;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
private ChessQRCodeConstants() {
throw new AssertionError(
- "No org.hedgecode.chess.ChessQRCodeConstants instances!"
+ "No org.hedgecode.chess.qrcode.ChessQRCodeConstants instances!"
);
}
import java.util.ResourceBundle;
-import org.hedgecode.chess.ChessQRCodeConstants;
-
/**
* Chess-specific QR Codes read/write/parse Exception.
*
package org.hedgecode.chess.qrcode;
/**
- * Mode of data type stored in Chess-specific QR Codes.
+ * Mode of data type stored in chess-specific QR Codes.
*
* @author Dmitry Samoshin aka gotty
*/
FEN,
TCD,
PGN,
- TCG;
+ TCG,
+ ZIP;
- static final int CODE_LENGTH = 3;
+ public static final int CODE_LENGTH = 3;
- boolean isPosition() {
+ public boolean isPosition() {
return FEN.equals(this) || TCD.equals(this);
}
- boolean isGame() {
+ public boolean isGame() {
return PGN.equals(this) || TCG.equals(this);
}
+ public boolean isArchive() {
+ return ZIP.equals(this);
+ }
+
public static ChessQRCodeMode byCode(String code) {
for (ChessQRCodeMode mode : ChessQRCodeMode.values()) {
if (mode.name().equals(code))
import com.google.zxing.qrcode.decoder.Decoder;
import com.google.zxing.qrcode.detector.Detector;
-import org.hedgecode.chess.ChessQRCodeConstants;
-
/**
* Chess-specific QR Codes reader (image decoder).
*
private static ChessQRCodeReader _instance = new ChessQRCodeReader();
- private ChessQRCodeReader() {
+ protected ChessQRCodeReader() {
decoder = new Decoder();
}
);
}
- ChessQRCodeMode mode = ChessQRCodeMode.byCode(
- decoderResult.getText().substring(0, ChessQRCodeMode.CODE_LENGTH)
- );
-
- if (mode == null) {
- throw new ChessQRCodeException(
- ChessQRCodeException.Type.READ, "read.unknown.chess.mode"
- );
- }
-
- return new ChessQRResult(
- mode,
- decoderResult.getText().substring(ChessQRCodeMode.CODE_LENGTH)
- );
+ return createResult(decoderResult);
/*
ResultPoint[] points = detectorResult.getPoints();
*/
}
+ protected ChessQRResult createResult(DecoderResult decoderResult) throws ChessQRCodeException {
+ String result = decoderResult.getText();
+
+ ChessQRCodeMode mode = ChessQRResult.getMode(result);
+ if (mode == null) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.READ, "read.unknown.chess.mode"
+ );
+ }
+
+ return new ChessQRResult(
+ mode,
+ ChessQRResult.getContents(result)
+ );
+ }
+
public static ChessQRCodeReader getInstance() {
return _instance;
}
public static void main(String[] args) {
try {
ChessQRResult qrCodeResult = ChessQRCodeReader.getInstance().read(
- new File("MyQRCode.png")
+ new File("qrcode.png")
);
System.out.println("Decoded format = " + qrCodeResult.getMode());
System.out.println("Decoded text = " + qrCodeResult.getContents());
import com.google.zxing.qrcode.encoder.Encoder;
import com.google.zxing.qrcode.encoder.QRCode;
-import org.hedgecode.chess.ChessQRCodeConstants;
import org.hedgecode.chess.img.ImageFormat;
/**
private static final int DEF_QUIET_ZONE_SIZE = 4;
private static final int DEF_QRCODE_BIT_SIZE = 250;
+ private static final int MIN_QRCODE_BIT_SIZE = 50;
private static final ErrorCorrectionLevel DEF_ERR_CORR_LEVEL = ErrorCorrectionLevel.H; // todo: Q
private static ChessQRCodeWriter _instance = new ChessQRCodeWriter();
- private ChessQRCodeWriter() {
+ protected ChessQRCodeWriter() {
}
public void write(ChessQRCodeMode mode, String contents, ImageFormat format, String qrCodeFilePath)
);
}
- private BitMatrix encode(
+ protected BitMatrix encode(
ChessQRCodeMode mode,
String contents,
int width, int height,
);
}
- if (width < 0 || height < 0) { // todo
+ if (Math.min(width, height) < MIN_QRCODE_BIT_SIZE) { // todo: check for Version
throw new ChessQRCodeException(
ChessQRCodeException.Type.WRITE, "write.qrcode.size.incorrect"
);
}
+ String qrCodeContents = mode.name().concat(contents);
+
int quietZone = DEF_QUIET_ZONE_SIZE;
ErrorCorrectionLevel errorCorrectionLevel = DEF_ERR_CORR_LEVEL;
}
hints = newHints;
- String qrCodeText = mode.name().concat(contents);
-
QRCode qrCode;
try {
qrCode = Encoder.encode(
- qrCodeText, errorCorrectionLevel, hints
+ qrCodeContents, errorCorrectionLevel, hints
);
} catch (WriterException e) {
throw new ChessQRCodeException(
ChessQRCodeMode.FEN,
"rnbqkbnr/ppp1pppp/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 2",
ImageFormat.PNG,
- "./MyQRCode.png"
+ "./qrcode.png"
);
/*
ChessQRCodeWriter.getInstance().write(
"11.Bf4 b5 12.a4 Bb7 13.Re1 Nd5 14.Bg3 Kc8 15.axb5 cxb5 16.Qd3 Bc6 \n" +
"17.Bf5 exf5 18.Rxe7 Bxe7 19.c4 1-0",
ImageFormat.PNG,
- "./MyQRCode.png"
+ "./qrcode.png"
);
*/
} catch (ChessQRCodeException e) {
static ByteMatrix embedChessLogoPattern(ByteMatrix byteMatrix) {
- if (byteMatrix == null || byteMatrix.getWidth() < CHESS_LOGO_PATTERN_LENGTH + 14) // todo: 14
- return null;
+ if (byteMatrix == null || byteMatrix.getWidth() < CHESS_LOGO_PATTERN_LENGTH + 14)
+ return null; // todo: check for Version
int xStart = (byteMatrix.getWidth() - CHESS_LOGO_PATTERN_LENGTH) / 2;
int yStart = (byteMatrix.getHeight() - CHESS_LOGO_PATTERN_LENGTH) / 2;
import org.hedgecode.chess.position.Position;
/**
- * Result storage for Chess-specific QR Codes data.
+ * Result storage for chess-specific QR Codes data.
*
* @author Dmitry Samoshin aka gotty
*/
private Position position;
private Game game;
- ChessQRResult(ChessQRCodeMode mode, String contents) {
+ public ChessQRResult(ChessQRCodeMode mode, String contents) {
this.mode = mode;
this.contents = contents;
}
+/*
ChessQRResult(Position position) {
this.position = position;
}
ChessQRResult(Game game) {
this.game = game;
}
+*/
public ChessQRCodeMode getMode() {
return mode;
}
}
+ public static ChessQRCodeMode getMode(String contents) {
+ return ChessQRCodeMode.byCode(
+ contents.substring(0, ChessQRCodeMode.CODE_LENGTH)
+ );
+ }
+
+ public static String getContents(String contents) {
+ return contents.substring(ChessQRCodeMode.CODE_LENGTH);
+ }
+
}
--- /dev/null
+/*
+ * Copyright (c) 2018-2019. Developed by Hedgecode.
+ *
+ * Licensed 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.hedgecode.chess.qrcode.zip;
+
+import java.io.File;
+
+import com.google.zxing.common.DecoderResult;
+
+import org.hedgecode.chess.qrcode.ChessQRCodeException;
+import org.hedgecode.chess.qrcode.ChessQRCodeMode;
+import org.hedgecode.chess.qrcode.ChessQRCodeReader;
+import org.hedgecode.chess.qrcode.ChessQRResult;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ZipChessQRCodeReader extends ChessQRCodeReader {
+
+ private static ZipChessQRCodeReader _instance = new ZipChessQRCodeReader();
+
+ protected ZipChessQRCodeReader() {
+ super();
+ }
+
+ @Override
+ protected ChessQRResult createResult(DecoderResult decoderResult) throws ChessQRCodeException {
+ String result = decoderResult.getText();
+ ChessQRCodeMode mode = ChessQRResult.getMode(result);
+
+ if (ChessQRCodeMode.ZIP.equals(mode)) {
+ String contents = ZipContentInflater.inflate(
+ ChessQRResult.getContents(result)
+ );
+
+ mode = ChessQRResult.getMode(contents);
+ if (mode == null) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.READ, "read.unknown.chess.mode"
+ );
+ }
+
+ return new ChessQRResult(
+ mode,
+ ChessQRResult.getContents(contents)
+ );
+ } else {
+ return super.createResult(decoderResult);
+ }
+ }
+
+ public static ZipChessQRCodeReader getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) {
+ try {
+ ChessQRResult qrCodeResult = ZipChessQRCodeReader.getInstance().read(
+ new File("qrcode.png")
+ );
+ System.out.println("Decoded format = " + qrCodeResult.getMode());
+ System.out.println("Decoded text = " + qrCodeResult.getContents());
+ } catch (ChessQRCodeException e) {
+ System.out.println("Could not decode QR Code. Exception: " + e.getMessage());
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018-2019. Developed by Hedgecode.
+ *
+ * Licensed 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.hedgecode.chess.qrcode.zip;
+
+import java.util.Map;
+
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.common.BitMatrix;
+import org.hedgecode.chess.img.ImageFormat;
+import org.hedgecode.chess.qrcode.ChessQRCodeException;
+import org.hedgecode.chess.qrcode.ChessQRCodeMode;
+import org.hedgecode.chess.qrcode.ChessQRCodeWriter;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ZipChessQRCodeWriter extends ChessQRCodeWriter {
+
+ private static ChessQRCodeWriter _instance = new ZipChessQRCodeWriter();
+
+ protected ZipChessQRCodeWriter() {
+ super();
+ }
+
+ @Override
+ protected BitMatrix encode(
+ ChessQRCodeMode mode,
+ String contents,
+ int width, int height,
+ Map<EncodeHintType,?> hints)
+ throws ChessQRCodeException
+ {
+ if (mode == null || mode.isArchive()) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.qrcode.mode.null"
+ );
+ }
+
+ if (contents == null || contents.isEmpty()) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.qrcode.contents.empty"
+ );
+ }
+
+ String zipContents = ZipContentDeflater.deflate(
+ mode.name().concat(contents)
+ );
+
+ return super.encode(
+ ChessQRCodeMode.ZIP, zipContents, width, height, hints
+ );
+ }
+
+ public static ChessQRCodeWriter getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) {
+ try {
+ ZipChessQRCodeWriter.getInstance().write(
+ ChessQRCodeMode.PGN,
+ "1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nd7 5.Ng5 Ngf6 6.Bd3 e6 7.N1f3 h6\n" +
+ "8.Nxe6 Qe7 9.O-O fxe6 10.Bg6+ Kd8 {Каспаров встряхнул головой} \n" +
+ "11.Bf4 b5 12.a4 Bb7 13.Re1 Nd5 14.Bg3 Kc8 15.axb5 cxb5 16.Qd3 Bc6 \n" +
+ "17.Bf5 exf5 18.Rxe7 Bxe7 19.c4 1-0",
+ ImageFormat.PNG,
+ "./qrcode.png"
+ );
+ } catch (ChessQRCodeException e) {
+ System.out.println("Could not generate QR Code, Exception: " + e.getMessage());
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018-2019. Developed by Hedgecode.
+ *
+ * Licensed 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.hedgecode.chess.qrcode.zip;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+
+import org.hedgecode.chess.qrcode.ChessQRCodeConstants;
+import org.hedgecode.chess.qrcode.ChessQRCodeException;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ZipContentDeflater {
+
+ public static String deflate(String contents) throws ChessQRCodeException {
+ byte[] bytes = contents.getBytes(
+ ChessQRCodeConstants.CHARSET
+ );
+ if (bytes.length > ZipContentUtils.getMaxContentLength()) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.PARSE, "zip.max.length.error"
+ );
+ }
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ DeflaterOutputStream zout = new DeflaterOutputStream(
+ bout, new Deflater(Deflater.BEST_COMPRESSION)
+ );
+ try {
+ try {
+ zout.write(bytes);
+ } finally {
+ zout.close();
+ bout.close();
+ }
+ } catch (IOException e) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.PARSE, "zip.deflate.write.error", e.getMessage()
+ );
+ }
+ return ZipContentUtils.base64Encode(
+ ZipContentUtils.concat(
+ bytes.length,
+ bout.toByteArray()
+ )
+ );
+ }
+
+
+ public static void main(String[] args) throws ChessQRCodeException {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 10; ++i) {
+ sb.append(i).append("bla-bla-bla").append(i);
+ }
+ String zipContents = ZipContentDeflater.deflate(sb.toString());
+ System.out.println("Zip Contents: " + zipContents);
+ System.out.println("Zip length: " + zipContents.length());
+ String contents = ZipContentInflater.inflate(zipContents);
+ System.out.println("Unzip Contents: " + contents);
+ System.out.println("Unziip length: " + contents.length());
+ System.out.println("Equals: " + sb.toString().equals(contents));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018-2019. Developed by Hedgecode.
+ *
+ * Licensed 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.hedgecode.chess.qrcode.zip;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.zip.InflaterInputStream;
+
+import org.hedgecode.chess.qrcode.ChessQRCodeConstants;
+import org.hedgecode.chess.qrcode.ChessQRCodeException;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ZipContentInflater {
+
+ public static String inflate(String zipContents) throws ChessQRCodeException {
+ byte[] zipBytes = ZipContentUtils.base64Decode(zipContents);
+ int length = ZipContentUtils.getZipLength(zipBytes);
+ if (length > ZipContentUtils.getMaxContentLength()) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.PARSE, "zip.max.length.error"
+ );
+ }
+ byte[] resultBytes = new byte[length];
+ InflaterInputStream zin = new InflaterInputStream(
+ new ByteArrayInputStream(
+ ZipContentUtils.getZipBytes(zipBytes)
+ )
+ );
+ try {
+ try {
+ length = zin.read(resultBytes, 0, length); // todo : check length
+ } finally {
+ zin.close();
+ }
+ } catch (IOException e) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.PARSE, "zip.inflate.read.error", e.getMessage()
+ );
+ }
+ return new String(
+ resultBytes, 0, length, ChessQRCodeConstants.CHARSET
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018-2019. Developed by Hedgecode.
+ *
+ * Licensed 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.hedgecode.chess.qrcode.zip;
+
+import java.util.Arrays;
+import java.util.Base64;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ZipContentUtils {
+
+ private static final int LENGTH_BYTE_COUNT = 4;
+
+ private static final int MAX_CONTENT_LENGTH = 65536;
+
+ public static int getMaxContentLength() {
+ return MAX_CONTENT_LENGTH;
+ }
+
+ public static int getZipLength(byte[] zipBytes) {
+ return fromByteArray(
+ Arrays.copyOf(zipBytes, LENGTH_BYTE_COUNT)
+ );
+ }
+
+ public static byte[] getZipBytes(byte[] zipBytes) {
+ return Arrays.copyOfRange(
+ zipBytes, LENGTH_BYTE_COUNT, zipBytes.length
+ );
+ }
+
+ public static byte[] concat(int length, byte[] bytes) {
+ return concat(
+ toByteArray(length),
+ bytes
+ );
+ }
+
+ public static String base64Encode(byte[] bytes) {
+ return Base64.getEncoder().encodeToString(bytes);
+ }
+
+ public static byte[] base64Decode(String value) {
+ return Base64.getDecoder().decode(value);
+ }
+
+ private static byte[] toByteArray(int value) {
+ return new byte[] {
+ (byte) (value >> 24),
+ (byte) (value >> 16),
+ (byte) (value >> 8),
+ (byte) (value)
+ };
+ }
+
+ private static int fromByteArray(byte[] bytes) {
+ return bytes[0] << 24
+ | (bytes[1] & 0xFF) << 16
+ | (bytes[2] & 0xFF) << 8
+ | (bytes[3] & 0xFF);
+ }
+
+ private static byte[] concat(byte[]... byteArrays) {
+ int length = 0;
+ for (byte[] bytes : byteArrays) {
+ length += bytes.length;
+ }
+ byte[] concatBytes = new byte[length];
+ length = 0;
+ for (byte[] bytes : byteArrays) {
+ if (bytes.length == 0)
+ continue;
+ System.arraycopy(bytes, 0, concatBytes, length, bytes.length);
+ length += bytes.length;
+ }
+ return concatBytes;
+ }
+
+ private ZipContentUtils() {
+ throw new AssertionError(
+ "No org.hedgecode.chess.qrcode.zip.ZipContentUtils instances!"
+ );
+ }
+
+}
write.qrcode.size.incorrect=Incorrect QR Code size specified
write.qrcode.chess.incorrect=Specified size is not suitable for chess QR Code
write.zxing.qrcode.error=Error encoding of QR code
+zip.max.length.error=Content length exceeds maximum size
+zip.deflate.write.error=Error deflating of content
+zip.inflate.read.error=Error inflating of content
write.qrcode.size.incorrect=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u043E \u0437\u0430\u0434\u0430\u043D \u0440\u0430\u0437\u043C\u0435\u0440 QR \u043A\u043E\u0434\u0430
write.qrcode.chess.incorrect=\u0417\u0430\u0434\u0430\u043D\u043D\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440 \u043D\u0435 \u043F\u043E\u0434\u0445\u043E\u0434\u0438\u0442 \u0434\u043B\u044F \u0448\u0430\u0445\u043C\u0430\u0442\u043D\u043E\u0433\u043E QR \u043A\u043E\u0434\u0430
write.zxing.qrcode.error=\u041E\u0448\u0438\u0431\u043A\u0430 \u043A\u043E\u0434\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F QR \u043A\u043E\u0434\u0430
+zip.max.length.error=\u0414\u043B\u0438\u043D\u0430 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0433\u043E \u043F\u0440\u0435\u0432\u044B\u0448\u0430\u0435\u0442 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440
+zip.deflate.write.error=\u041E\u0448\u0438\u0431\u043A\u0430 \u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0433\u043E
+zip.inflate.read.error=\u041E\u0448\u0438\u0431\u043A\u0430 \u0440\u0430\u0437\u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0433\u043E