--- /dev/null
+*.o
+.*.sw*
--- /dev/null
+CFLAGS = -Isrc -g -Wall -Wextra -Wconversion
+
+OBJS = $(patsubst %.c, %.o, $(wildcard src/*.o))
+TEST_OBJS = $(patsubst %.c, %.o, $(wildcard test/*.o))
+TESTS = $(patsubst %.c, %, $(wildcard test/*.c))
+RUN_TESTS = $(addprefix run_, $(TESTS))
+
+default: $(RUN_TESTS)
+
+$(RUN_TESTS): run_%: %
+ $^
+
+all: $(OBJS)
+
+$(OBJS): %.o: %.h src/tans_constants.h
+$(TEST_OBJS): test/test.h $(OBJS)
+
+test/test_tans_bit_reader.o: src/tans_buf_bit_reader.h src/tans_file_bit_reader.h src/tans_bit_reader.h
+test/test_tans_bit_reader: src/tans_buf_bit_reader.o src/tans_file_bit_reader.o
+test/test_tans_bit_writer.o: src/tans_buf_bit_writer.h src/tans_bit_writer.h
+test/test_tans_bit_writer: src/tans_buf_bit_writer.o
+test/test_tans_encode_st.o: src/tans_buf_bit_writer.h src/tans_bit_writer.h src/tans_encode_st.h src/tans_symbol_tbl.h src/tans_freq_tbl.h
+test/test_tans_encode_st: src/tans_buf_bit_writer.o src/tans_encode_st.o src/tans_encode_tbl.o src/tans_symbol_tbl.o
+
+clean:
+ rm -f $(OBJS)
+ rm -f $(TEST_OBJS)
+ rm -f $(TESTS)
+
+.PHONY: default all clean $(RUN_TESTS)
--- /dev/null
+#pragma once
+
+static uint16_t floor_log2(uint16_t x)
+{
+ if (x <= 1) return 0;
+ if (x <= 2) return 1;
+ if (x <= 4) return 2;
+ if (x <= 8) return 3;
+ if (x <= 16) return 4;
+ if (x <= 32) return 5;
+ if (x <= 64) return 6;
+ if (x <= 128) return 7;
+ if (x <= 256) return 8;
+ if (x <= 512) return 9;
+ if (x <= 1024) return 10;
+ if (x <= 2048) return 11;
+ if (x <= 4096) return 12;
+ if (x <= 8192) return 13;
+ if (x <= 16384) return 14;
+ if (x <= 32768) return 15;
+ /*if (x <= 65536)*/ return 16;
+}
--- /dev/null
+#pragma once
+
+#include <stdint.h>
+
+struct tans_bit_reader;
+
+struct tans_bit_reader_ops {
+ uint16_t (*read)(struct tans_bit_reader *self, uint8_t bits);
+};
+
+struct tans_bit_reader {
+ const struct tans_bit_reader_ops *vtable;
+};
--- /dev/null
+#pragma once
+
+#include <stdint.h>
+
+struct tans_bit_writer;
+
+struct tans_bit_writer_ops {
+ uint16_t (*write)(struct tans_bit_writer *self, uint16_t value, uint8_t bits);
+};
+
+struct tans_bit_writer {
+ const struct tans_bit_writer_ops *vtable;
+};
--- /dev/null
+#include "tans_buf_bit_reader.h"
+
+static uint16_t tans_buf_bit_reader_read(struct tans_bit_reader *reader, uint8_t bits)
+{
+ struct tans_buf_bit_reader *self = (struct tans_buf_bit_reader *) reader;
+ uint32_t bit = self->bit % 8;
+ uint32_t byte = self->bit / 8;
+
+ if (bits == 0 || self->bit + bits > self->len * 8) {
+ return (uint16_t) -1;
+ }
+
+ self->bit += bits;
+
+ if (bit + bits <= 8) {
+ return (uint16_t) (((1 << bits) - 1) & (self->buf[byte] >> bit));
+ } else if (bit + bits <= 16) {
+ return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte] | (self->buf[byte+1] << 8)) >> bit));
+ } else if (bit + bits <= 24) {
+ return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte] | (self->buf[byte+1] << 8) | (self->buf[byte+2] << 16)) >> bit));
+ } else {
+ return (uint16_t) -1;
+ }
+}
+
+static const struct tans_bit_reader_ops vtable = {
+ .read = tans_buf_bit_reader_read,
+};
+
+void tans_buf_bit_reader_init(struct tans_buf_bit_reader *self, const uint8_t *buf, uint32_t len)
+{
+ self->vtable = &vtable;
+ self->bit = 0;
+ self->len = len;
+ self->buf = buf;
+}
--- /dev/null
+#pragma once
+
+#include "tans_bit_reader.h"
+
+struct tans_buf_bit_reader {
+ const struct tans_bit_reader_ops *vtable;
+ uint32_t bit;
+ uint32_t len;
+ const uint8_t *buf;
+};
+
+void tans_buf_bit_reader_init(struct tans_buf_bit_reader *self, const uint8_t *buf, uint32_t len);
--- /dev/null
+#include "tans_buf_bit_writer.h"
+
+static uint16_t tans_buf_bit_writer_write(struct tans_bit_writer *writer, uint16_t value, uint8_t bits)
+{
+ struct tans_buf_bit_writer *self = (struct tans_buf_bit_writer *) writer;
+ uint32_t bit = self->bit % 8;
+ uint32_t byte = self->bit / 8;
+
+ if (bits == 0) {
+ return 0;
+ }
+
+ if (self->bit + bits > self->len * 8) {
+ return (uint16_t) -1;
+ }
+
+ self->bit += bits;
+
+ if (bit + bits <= 8) {
+ self->buf[byte] |= (uint8_t) ((value & ((1 << bits) - 1)) << bit);
+ return bits;
+ } else if (bit + bits <= 16) {
+ self->buf[byte] |= (uint8_t) ((value << bit) & 0xff);
+ self->buf[byte+1] |= (uint8_t) ((value & ((1 << bits) - 1)) >> (8 - bit));
+ return bits;
+ } else if (bit + bits <= 24) {
+ self->buf[byte] |= (uint8_t) ((value << bit) & 0xff);
+ self->buf[byte+1] |= (uint8_t) ((value >> (8 - bit)) & 0xff);
+ self->buf[byte+2] |= (uint8_t) ((value & ((1 << bits) - 1)) >> (16 - bit));
+ return bits;
+ } else {
+ return (uint16_t) -1;
+ }
+}
+
+static const struct tans_bit_writer_ops vtable = {
+ .write = tans_buf_bit_writer_write,
+};
+
+void tans_buf_bit_writer_init(struct tans_buf_bit_writer *self, uint8_t *buf, uint32_t len)
+{
+ self->vtable = &vtable;
+ self->bit = 0;
+ self->len = len;
+ self->buf = buf;
+}
--- /dev/null
+#pragma once
+
+#include "tans_bit_writer.h"
+
+struct tans_buf_bit_writer {
+ const struct tans_bit_writer_ops *vtable;
+ uint32_t bit;
+ uint32_t len;
+ uint8_t *buf;
+};
+
+void tans_buf_bit_writer_init(struct tans_buf_bit_writer *self, uint8_t *buf, uint32_t len);
--- /dev/null
+#pragma once
+
+#define TANS_R 10
+#define TANS_L (1 << TANS_R)
--- /dev/null
+#include "tans_decode_st.h"
+
+void tans_decode_st_init(struct tans_decode_st *self, struct tans_symbol_tbl *symbol_tbl)
+{
+ tans_decode_tbl_init(&self->decode_tbl, symbol_tbl);
+ self->x = 0;
+}
+
+uint16_t tans_decode_st_next(struct tans_decode_st *self, struct tans_bit_reader *bit_reader)
+{
+ uint8_t ret;
+ uint16_t read;
+ struct tans_decode_tbl_entry t = self->decode_tbl.entries[self->x];
+
+ read = bit_reader->vtable->read(bit_reader, t.nb_bits);
+ if (read == -1) {
+ return -1;
+ }
+
+ ret = t.symbol;
+ self->x = t.new_x + read;
+
+ return (uint16_t) ret;
+}
--- /dev/null
+#pragma once
+
+#include "tans_decode_tbl.h"
+#include "tans_bit_reader.h"
+
+struct tans_decode_st {
+ struct tans_decode_tbl decode_tbl;
+ uint16_t x;
+};
+
+void tans_decode_st_init(struct tans_decode_st *self, struct tans_symbol_tbl *symbol_tbl);
+uint16_t tans_decode_st_next(struct tans_decode_st *self, struct tans_bit_reader *bit_reader);
--- /dev/null
+#include "tans_decode_tbl.h"
+
+#include "floor_log2.h"
+
+void tans_decode_tbl_init(struct tans_decode_tbl *self, struct tans_symbol_tbl *symbol_tbl)
+{
+ uint16_t i;
+ uint16_t x;
+ uint8_t s;
+
+ for (i = 0; i < TANS_L; ++i) {
+ s = self->entries[i].symbol = symbol_tbl->symbol[i];
+ x = symbol_tbl->entries[s].next++;
+ self->entries[s].nb_bits = TANS_R - floor_log2(x);
+ self->entries[s].new_x = (x << self->entries[s].nb_bits) - TANS_L;
+ }
+}
--- /dev/null
+#pragma once
+
+#include "tans_symbol_tbl.h"
+
+struct tans_decode_tbl_entry {
+ uint8_t symbol;
+ uint8_t nb_bits;
+ uint16_t new_x;
+};
+
+struct tans_decode_tbl {
+ struct tans_decode_tbl_entry entries[TANS_L];
+};
+
+void tans_decode_tbl_init(struct tans_decode_tbl *self, struct tans_symbol_tbl *symbol_tbl);
--- /dev/null
+#include "tans_encode_st.h"
+
+void tans_encode_st_init(struct tans_encode_st *self, const struct tans_symbol_tbl *symbol_tbl)
+{
+ self->symbol_tbl = *symbol_tbl;
+ tans_encode_tbl_init(&self->encode_tbl, &self->symbol_tbl);
+ self->x = 0;
+}
+
+uint16_t tans_encode_st_next(struct tans_encode_st *self, struct tans_bit_writer *bit_writer, uint8_t symbol)
+{
+ uint8_t nb_bits;
+ uint16_t written;
+
+ nb_bits = (uint8_t) ((self->x + TANS_L + self->symbol_tbl.entries[symbol].nb) >> (TANS_R + 1));
+ written = bit_writer->vtable->write(bit_writer, self->x + TANS_L, nb_bits);
+ if (written != nb_bits) {
+ return (uint16_t) -1;
+ }
+ self->x = self->encode_tbl.entries[self->symbol_tbl.entries[symbol].start + ((self->x + TANS_L) >> nb_bits)].x;
+
+ return written;
+}
--- /dev/null
+#pragma once
+
+#include "tans_encode_tbl.h"
+#include "tans_bit_writer.h"
+
+struct tans_encode_st {
+ struct tans_symbol_tbl symbol_tbl;
+ struct tans_encode_tbl encode_tbl;
+ uint16_t x;
+};
+
+void tans_encode_st_init(struct tans_encode_st *self, const struct tans_symbol_tbl *symbol_tbl);
+uint16_t tans_encode_st_next(struct tans_encode_st *self, struct tans_bit_writer *bit_writer, uint8_t symbol);
--- /dev/null
+#include "tans_encode_tbl.h"
+
+void tans_encode_tbl_init(struct tans_encode_tbl *self, struct tans_symbol_tbl *symbol_tbl)
+{
+ uint8_t s;
+ uint16_t x;
+
+ for (x = TANS_L; x < TANS_L << 1; ++x) {
+ s = symbol_tbl->symbol[x-TANS_L];
+ self->entries[symbol_tbl->entries[s].start + symbol_tbl->entries[s].next++].x = x - TANS_L;
+ }
+}
--- /dev/null
+#pragma once
+
+#include "tans_constants.h"
+#include "tans_symbol_tbl.h"
+
+struct tans_encode_tbl_entry {
+ uint16_t x;
+};
+
+struct tans_encode_tbl {
+ // TODO verify size of entries table
+ struct tans_encode_tbl_entry entries[TANS_L];
+};
+
+void tans_encode_tbl_init(struct tans_encode_tbl *self, struct tans_symbol_tbl *symbol_tbl);
--- /dev/null
+#include "tans_file_bit_reader.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+static uint16_t tans_file_bit_reader_read(struct tans_bit_reader *reader, uint8_t bits)
+{
+ struct tans_file_bit_reader *self = (struct tans_file_bit_reader *) reader;
+ ssize_t bytes_read;
+ uint32_t bit = self->bit % 8;
+ uint32_t byte = self->bit / 8;
+
+ if (bits == 0) {
+ return (uint16_t) -1;
+ }
+
+ while (self->len * 8 - self->bit < bits) {
+ memmove(self->buf, self->buf + byte, self->len - byte);
+ bytes_read = read(self->fd, self->buf + self->len, sizeof self->buf - self->len);
+ if (bytes_read <= 0) {
+ return (uint16_t) -1;
+ }
+ self->len += (uint32_t) bytes_read;
+ }
+
+ self->bit += bits;
+
+ if (bit + bits <= 8) {
+ return (uint16_t) (((1 << bits) - 1) & (self->buf[byte] >> bit));
+ } else if (bit + bits <= 16) {
+ return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte] >> bit) | (self->buf[byte+1] << (8 - bit))));
+ } else if (bit + bits <= 24) {
+ return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte] >> bit) | ((self->buf[byte+1] | (self->buf[byte+2] << 8)) << (8 - bit))));
+ } else {
+ return (uint16_t) -1;
+ }
+}
+
+static const struct tans_bit_reader_ops vtable = {
+ .read = tans_file_bit_reader_read,
+};
+
+int tans_file_bit_reader_init(struct tans_file_bit_reader *self, const char *filename)
+{
+ self->vtable = &vtable;
+ self->fd = open(filename, O_RDONLY | O_CLOEXEC);
+ self->bit = 0;
+ self->len = 0;
+
+ if (self->fd == -1) {
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+#pragma once
+
+#include "tans_bit_reader.h"
+
+#define TANS_FILE_BIT_READER_BUFSZ 1024
+
+struct tans_file_bit_reader {
+ const struct tans_bit_reader_ops *vtable;
+ int fd;
+ uint32_t bit;
+ uint32_t len;
+ uint8_t buf[TANS_FILE_BIT_READER_BUFSZ];
+};
+
+int tans_file_bit_reader_init(struct tans_file_bit_reader *self, const char *filename);
--- /dev/null
+#pragma once
+
+#include <stdint.h>
+
+struct tans_freq_tbl {
+ uint16_t freq[256];
+};
--- /dev/null
+#include "tans_symbol_tbl.h"
+
+#include "floor_log2.h"
+
+int tans_symbol_tbl_init(struct tans_symbol_tbl *self, const struct tans_freq_tbl *freq_tbl)
+{
+ uint16_t x, step, s, i, start, freq, k;
+
+ x = 0;
+ step = TANS_L*5/8 + 3;
+ start = 0;
+
+ for (s = 0; s < 256; ++s) {
+ freq = freq_tbl->freq[s];
+ self->entries[s].start = start;
+ self->entries[s].next = freq;
+ k = TANS_R - floor_log2(freq);
+ self->entries[s].nb = (uint16_t) ((k << (TANS_R + 1)) - (freq << k));
+ start += freq;
+ for (i = 0; i < freq; ++i) {
+ self->symbol[x] = (uint8_t) s;
+ x += step;
+ x %= TANS_L;
+ }
+ }
+
+ if (start != TANS_L) { // freq entries must add up to TANS_L
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+#pragma once
+
+#include "tans_constants.h"
+#include "tans_freq_tbl.h"
+
+struct tans_symbol_tbl_entry {
+ uint16_t nb;
+ uint16_t start;
+ uint16_t next;
+};
+
+struct tans_symbol_tbl {
+ uint8_t symbol[TANS_L];
+ struct tans_symbol_tbl_entry entries[256];
+};
+
+int tans_symbol_tbl_init(struct tans_symbol_tbl *self, const struct tans_freq_tbl *freq_tbl);
--- /dev/null
+#pragma once
+
+#include <stdio.h>
+
+enum test_result {
+ TEST_SUCCESS = 0x100,
+ TEST_SKIP = 0x101,
+ TEST_FAILURE = 0x102,
+};
+
+#define ASSERT_EQ(lhs, rhs) do { \
+ long a = (long) (lhs), b = (long) (rhs); \
+ if ((a) != (b)) { \
+ printf("ERROR: " #lhs " (%ld) != " #rhs " (%ld)\n", (a), (b)); \
+ return TEST_FAILURE; \
+ } \
+ } while(0)
+
+#define ASSERT_NE(lhs, rhs) do { \
+ long a = (long) (lhs), b = (long) (rhs); \
+ if ((a) == (b)) { \
+ printf("ERROR: " #lhs " (%ld) == " #rhs " (%ld)\n", (a), (b)); \
+ return TEST_FAILURE; \
+ } \
+ } while(0)
+
+#define RUN_TEST(test_fn) switch (test_fn()) { \
+ case TEST_SUCCESS: printf("PASS: " #test_fn "\n"); break; \
+ case TEST_SKIP: printf("SKIP: " #test_fn "\n"); break; \
+ case TEST_FAILURE: printf("FAIL: " #test_fn "\n"); return 1; \
+ default: printf("FAIL: " #test_fn "\n"); return 1; \
+}
+
--- /dev/null
+#include "test.h"
+
+#include "tans_buf_bit_reader.h"
+#include "tans_file_bit_reader.h"
+
+enum test_result test_tans_buf_bit_reader(void)
+{
+ struct tans_buf_bit_reader bit_reader;
+ uint8_t buf[8] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0xfd, 0x08, 0xfc};
+
+ tans_buf_bit_reader_init(&bit_reader, buf, sizeof buf);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 0), (uint16_t) -1);
+
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 8), 1);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 4), 0xf);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 6), 0x2f);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 2), 0);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 16), 0x3fe0);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 8), 0xd0);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 7), 0x0f);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 1), 1);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 3), 0);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 5), 0x18);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 4), 0xf);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 1), (uint16_t) -1);
+
+ return TEST_SUCCESS;
+}
+
+enum test_result test_tans_file_bit_reader(void)
+{
+ struct tans_file_bit_reader bit_reader;
+ uint8_t bits;
+
+ ASSERT_EQ(tans_file_bit_reader_init(&bit_reader, "/dev/zero"), 0);
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 0), (uint16_t) -1);
+
+ for (bits = 1; bits <= 16; ++bits) {
+ ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, bits), 0);
+ }
+
+ return TEST_SUCCESS;
+}
+
+int main(void)
+{
+ RUN_TEST(test_tans_buf_bit_reader);
+ RUN_TEST(test_tans_file_bit_reader);
+}
--- /dev/null
+#include "test.h"
+
+#include "tans_buf_bit_writer.h"
+
+enum test_result test_tans_buf_bit_writer(void)
+{
+ struct tans_buf_bit_writer buf_bit_writer;
+ struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer;
+ uint8_t buf[8] = {0};
+
+ tans_buf_bit_writer_init(&buf_bit_writer, buf, sizeof buf);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 0), 0);
+
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 1, 8), 8);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0xf, 4), 4);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x2f, 6), 6);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 2), 2);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x3fe0, 16), 16);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0xd0, 8), 8);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x0f, 7), 7);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 1, 1), 1);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 3), 3);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x18, 5), 5);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0xf, 4), 4);
+ ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 1), (uint16_t) -1);
+
+ ASSERT_EQ(buf[0], 0x01);
+ ASSERT_EQ(buf[1], 0xff);
+ ASSERT_EQ(buf[2], 0x02);
+ ASSERT_EQ(buf[3], 0xfe);
+ ASSERT_EQ(buf[4], 0x03);
+ ASSERT_EQ(buf[5], 0xfd);
+ ASSERT_EQ(buf[6], 0x08);
+ ASSERT_EQ(buf[7], 0xfc);
+
+ return TEST_SUCCESS;
+}
+
+int main(void)
+{
+ RUN_TEST(test_tans_buf_bit_writer);
+}
--- /dev/null
+#include "test.h"
+
+#include "tans_buf_bit_writer.h"
+#include "tans_encode_st.h"
+
+enum test_result test_tans_encode_st_equal_freq(void)
+{
+ struct tans_freq_tbl freq_tbl;
+ struct tans_symbol_tbl symbol_tbl;
+ struct tans_encode_st encode_st;
+ struct tans_buf_bit_writer buf_bit_writer;
+ struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer;
+ uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+ uint8_t buf[8] = {0};
+ uint16_t i;
+
+ for (i = 0; i < 256; ++i) {
+ freq_tbl.freq[i] = TANS_L / 256;
+ }
+ ASSERT_EQ(tans_symbol_tbl_init(&symbol_tbl, &freq_tbl), 0);
+ tans_encode_st_init(&encode_st, &symbol_tbl);
+ tans_buf_bit_writer_init(&buf_bit_writer, buf, sizeof buf);
+
+ for (i = 0; i < sizeof data; ++i) {
+ ASSERT_NE(tans_encode_st_next(&encode_st, bit_writer, data[i]), (uint16_t) -1);
+ }
+
+ ASSERT_EQ(buf_bit_writer.bit, buf_bit_writer.len * 8);
+ ASSERT_EQ(tans_encode_st_next(&encode_st, bit_writer, 0), (uint16_t) -1);
+
+ return TEST_SUCCESS;
+}
+
+int main(void)
+{
+ RUN_TEST(test_tans_encode_st_equal_freq);
+}