mirror of
https://github.com/zint/zint
synced 2024-11-16 20:57:25 +13:00
Ultra: Disable code compression by default
Ensures symbols are valid until better version of specification is available
This commit is contained in:
parent
c57b74a7e6
commit
b572bb513d
145
backend/ultra.c
145
backend/ultra.c
@ -1,7 +1,7 @@
|
|||||||
/* ultra.c - Ultracode
|
/* ultra.c - Ultracode
|
||||||
|
|
||||||
libzint - the open source barcode library
|
libzint - the open source barcode library
|
||||||
Copyright (C) 2019 Robin Stuart <rstuart114@gmail.com>
|
Copyright (C) 2020 Robin Stuart <rstuart114@gmail.com>
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions
|
modification, are permitted provided that the following conditions
|
||||||
@ -117,6 +117,18 @@ static const int tiles[] = {
|
|||||||
* Dated 2001-03-09
|
* Dated 2001-03-09
|
||||||
* Corrected thanks to input from Terry Burton */
|
* Corrected thanks to input from Terry Burton */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: Included here is an attempt to allow code compression within Ultracode. Unfortunately
|
||||||
|
* the copy of the standard this was written from was an early draft which includes self
|
||||||
|
* contradictions, so this is a "best guess" implementation. Because it is not guaranteed
|
||||||
|
* to be correct this compression is not applied by default. To enable compression set
|
||||||
|
*
|
||||||
|
* symbol->option_1 = ULTRA_COMPRESSION;
|
||||||
|
*
|
||||||
|
* Code compression should be enabled by default when is has been implemented according to
|
||||||
|
* a more reliable version of the specification.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Generate divisor polynomial gQ(x) for GF283() given the required ECC size, 3 to 101 */
|
/* Generate divisor polynomial gQ(x) for GF283() given the required ECC size, 3 to 101 */
|
||||||
void ultra_genPoly(short EccSize, unsigned short gPoly[], unsigned short gfPwr[], unsigned short gfLog[]) {
|
void ultra_genPoly(short EccSize, unsigned short gPoly[], unsigned short gfPwr[], unsigned short gfLog[]) {
|
||||||
int i, j;
|
int i, j;
|
||||||
@ -239,15 +251,8 @@ float look_ahead_eightbit(unsigned char source[], int in_length, int in_locn, ch
|
|||||||
|
|
||||||
letters_encoded = i - in_locn;
|
letters_encoded = i - in_locn;
|
||||||
|
|
||||||
//printf("8BIT FRAG: ");
|
|
||||||
//for (i = 0; i < codeword_count; i++) {
|
|
||||||
// printf("%d ", cw[i]);
|
|
||||||
//}
|
|
||||||
//printf("\n");
|
|
||||||
|
|
||||||
*cw_len = codeword_count;
|
*cw_len = codeword_count;
|
||||||
|
|
||||||
//printf("%d letters in %d codewords\n", letters_encoded, codeword_count);
|
|
||||||
if (codeword_count == 0) {
|
if (codeword_count == 0) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
} else {
|
} else {
|
||||||
@ -326,15 +331,8 @@ float look_ahead_ascii(unsigned char source[], int in_length, int in_locn, char
|
|||||||
|
|
||||||
letters_encoded = i - in_locn;
|
letters_encoded = i - in_locn;
|
||||||
|
|
||||||
//printf("ASCII FRAG: ");
|
|
||||||
//for (i = 0; i < codeword_count; i++) {
|
|
||||||
// printf("%d ", cw[i]);
|
|
||||||
//}
|
|
||||||
//printf("\n");
|
|
||||||
|
|
||||||
*cw_len = codeword_count;
|
*cw_len = codeword_count;
|
||||||
|
|
||||||
//printf("%d letters in %d codewords\n", letters_encoded, codeword_count);
|
|
||||||
if (codeword_count == 0) {
|
if (codeword_count == 0) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
} else {
|
} else {
|
||||||
@ -529,7 +527,7 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_locn, char cu
|
|||||||
if (pad == 3) {
|
if (pad == 3) {
|
||||||
pad = 0;
|
pad = 0;
|
||||||
}
|
}
|
||||||
//printf("Pad = %d\n", pad);
|
|
||||||
for (i = 0; i < pad; i++) {
|
for (i = 0; i < pad; i++) {
|
||||||
subcw[subcodeword_count] = 42; // Latch to other C43 set used as pad
|
subcw[subcodeword_count] = 42; // Latch to other C43 set used as pad
|
||||||
subcodeword_count++;
|
subcodeword_count++;
|
||||||
@ -537,12 +535,6 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_locn, char cu
|
|||||||
|
|
||||||
letters_encoded = sublocn - in_locn;
|
letters_encoded = sublocn - in_locn;
|
||||||
|
|
||||||
//printf("C43 SUBFRAG: ");
|
|
||||||
//for (i = 0; i < subcodeword_count; i++) {
|
|
||||||
// printf("%d ", subcw[i]);
|
|
||||||
//}
|
|
||||||
//printf("\n");
|
|
||||||
|
|
||||||
for (i = 0; i < subcodeword_count; i += 3) {
|
for (i = 0; i < subcodeword_count; i += 3) {
|
||||||
base43_value = (43 * 43 * subcw[i]) + (43 * subcw[i + 1]) + subcw[i + 2];
|
base43_value = (43 * 43 * subcw[i]) + (43 * subcw[i + 1]) + subcw[i + 2];
|
||||||
cw[codeword_count] = base43_value / 282;
|
cw[codeword_count] = base43_value / 282;
|
||||||
@ -551,15 +543,8 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_locn, char cu
|
|||||||
codeword_count++;
|
codeword_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// printf("C43 FRAG: ");
|
|
||||||
//for (i = 0; i < codeword_count; i++) {
|
|
||||||
// printf("%d ", cw[i]);
|
|
||||||
//}
|
|
||||||
//printf("\n");
|
|
||||||
|
|
||||||
*cw_len = codeword_count;
|
*cw_len = codeword_count;
|
||||||
|
|
||||||
//printf("%d letters in %d codewords\n", letters_encoded, codeword_count);
|
|
||||||
if (codeword_count == 0) {
|
if (codeword_count == 0) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
} else {
|
} else {
|
||||||
@ -585,13 +570,13 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou
|
|||||||
int gs1 = 0;
|
int gs1 = 0;
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
unsigned char crop_source[in_length];
|
unsigned char crop_source[in_length + 1];
|
||||||
char mode[in_length];
|
char mode[in_length + 1];
|
||||||
int cw_fragment[in_length];
|
int cw_fragment[in_length + 1];
|
||||||
#else
|
#else
|
||||||
unsigned char * crop_source = (unsigned char *) _alloca(in_length * sizeof (unsigned char));
|
unsigned char * crop_source = (unsigned char *) _alloca((in_length + 1) * sizeof (unsigned char));
|
||||||
char * mode = (char *) _alloca(in_length * sizeof (char));
|
char * mode = (char *) _alloca(in_length + 1 * sizeof (char));
|
||||||
int * cw_fragment = (int *) _alloca(in_length * sizeof (int));
|
int * cw_fragment = (int *) _alloca(in_length + 1 * sizeof (int));
|
||||||
#endif /* _MSC_VER */
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
/* Section 7.6.2 indicates that ECI \000003 to \811799 are supported */
|
/* Section 7.6.2 indicates that ECI \000003 to \811799 are supported */
|
||||||
@ -608,6 +593,11 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou
|
|||||||
symbol_mode = EIGHTBIT_MODE;
|
symbol_mode = EIGHTBIT_MODE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (symbol->option_1 != ULTRA_COMPRESSION) {
|
||||||
|
// Force eight-bit mode by default as other modes are poorly documented
|
||||||
|
symbol_mode = EIGHTBIT_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
if (symbol->output_options & READER_INIT) {
|
if (symbol->output_options & READER_INIT) {
|
||||||
/* Reader Initialisation mode */
|
/* Reader Initialisation mode */
|
||||||
@ -715,28 +705,35 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt encoding in all three modes to see which offers best compaction and store results */
|
/* Attempt encoding in all three modes to see which offers best compaction and store results */
|
||||||
current_mode = symbol_mode;
|
if (symbol->option_1 != ULTRA_COMPRESSION) {
|
||||||
input_locn = 0;
|
current_mode = symbol_mode;
|
||||||
do {
|
input_locn = 0;
|
||||||
end_char = input_locn + PREDICT_WINDOW;
|
do {
|
||||||
eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1);
|
end_char = input_locn + PREDICT_WINDOW;
|
||||||
ascii_score = look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length, gs1);
|
eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1);
|
||||||
c43_score = look_ahead_c43(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1);
|
ascii_score = look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length, gs1);
|
||||||
|
c43_score = look_ahead_c43(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1);
|
||||||
|
|
||||||
mode[input_locn] = 'a';
|
mode[input_locn] = 'a';
|
||||||
current_mode = ASCII_MODE;
|
current_mode = ASCII_MODE;
|
||||||
|
|
||||||
if ((c43_score > ascii_score) && (c43_score > eightbit_score)) {
|
if ((c43_score > ascii_score) && (c43_score > eightbit_score)) {
|
||||||
mode[input_locn] = 'c';
|
mode[input_locn] = 'c';
|
||||||
current_mode = C43_MODE;
|
current_mode = C43_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((eightbit_score > ascii_score) && (eightbit_score > c43_score)) {
|
if ((eightbit_score > ascii_score) && (eightbit_score > c43_score)) {
|
||||||
|
mode[input_locn] = '8';
|
||||||
|
current_mode = EIGHTBIT_MODE;
|
||||||
|
}
|
||||||
|
input_locn++;
|
||||||
|
} while (input_locn < crop_length);
|
||||||
|
} else {
|
||||||
|
// Force eight-bit mode
|
||||||
|
for (input_locn = 0; input_locn < crop_length; input_locn++) {
|
||||||
mode[input_locn] = '8';
|
mode[input_locn] = '8';
|
||||||
current_mode = EIGHTBIT_MODE;
|
|
||||||
}
|
}
|
||||||
input_locn++;
|
}
|
||||||
} while (input_locn < crop_length);
|
|
||||||
mode[input_locn] = '\0';
|
mode[input_locn] = '\0';
|
||||||
|
|
||||||
/* Use results from test to perform actual mode switching */
|
/* Use results from test to perform actual mode switching */
|
||||||
@ -784,9 +781,6 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou
|
|||||||
input_locn += block_length;
|
input_locn += block_length;
|
||||||
} while (input_locn < crop_length);
|
} while (input_locn < crop_length);
|
||||||
|
|
||||||
//printf("RED: %s\n", crop_source);
|
|
||||||
//printf("MOD: %s\n", mode);
|
|
||||||
|
|
||||||
return codeword_count;
|
return codeword_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -823,12 +817,9 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si
|
|||||||
|
|
||||||
data_cw_count = ultra_generate_codewords(symbol, source, in_length, data_codewords);
|
data_cw_count = ultra_generate_codewords(symbol, source, in_length, data_codewords);
|
||||||
|
|
||||||
printf("Codewords returned = %d\n", data_cw_count);
|
if (symbol->debug) {
|
||||||
|
printf("Codewords returned = %d\n", data_cw_count);
|
||||||
//for (int i = 0; i < data_cw_count; i++) {
|
}
|
||||||
// printf("%d ", data_codewords[i]);
|
|
||||||
//}
|
|
||||||
//printf("\n");
|
|
||||||
|
|
||||||
/* Default ECC level is EC2 */
|
/* Default ECC level is EC2 */
|
||||||
if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) {
|
if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) {
|
||||||
@ -850,7 +841,9 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si
|
|||||||
}
|
}
|
||||||
acc = qcc - 3;
|
acc = qcc - 3;
|
||||||
|
|
||||||
printf("ECC codewords: %d\n", qcc);
|
if (symbol->debug) {
|
||||||
|
printf("ECC codewords: %d\n", qcc);
|
||||||
|
}
|
||||||
|
|
||||||
/* Maximum capacity is 282 codewords */
|
/* Maximum capacity is 282 codewords */
|
||||||
total_cws = data_cw_count + qcc + 5;
|
total_cws = data_cw_count + qcc + 5;
|
||||||
@ -874,7 +867,9 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si
|
|||||||
columns = (total_cws / rows) + 1;
|
columns = (total_cws / rows) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Calculated size is %d rows by %d columns\n", rows, columns);
|
if (symbol->debug) {
|
||||||
|
printf("Calculated size is %d rows by %d columns\n", rows, columns);
|
||||||
|
}
|
||||||
|
|
||||||
/* Insert MCC and ACC into data codewords */
|
/* Insert MCC and ACC into data codewords */
|
||||||
for (i = 282; i > 2; i--) {
|
for (i = 282; i > 2; i--) {
|
||||||
@ -904,11 +899,13 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si
|
|||||||
}
|
}
|
||||||
codeword[locn++] = qcc; // QCC
|
codeword[locn++] = qcc; // QCC
|
||||||
|
|
||||||
printf("Rearranged codewords with ECC:\n");
|
if (symbol->debug) {
|
||||||
for (i = 0; i < locn; i++) {
|
printf("Rearranged codewords with ECC:\n");
|
||||||
printf("%d ", codeword[i]);
|
for (i = 0; i < locn; i++) {
|
||||||
|
printf("%d ", codeword[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
total_height = (rows * 6) + 1;
|
total_height = (rows * 6) + 1;
|
||||||
total_width = columns + 6 + (columns / 15);
|
total_width = columns + 6 + (columns / 15);
|
||||||
@ -976,7 +973,7 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si
|
|||||||
tilex++;
|
tilex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//printf("[%d] = %s\n", codeword[i], tilepat);
|
|
||||||
for (j = 0; j < 5; j++) {
|
for (j = 0; j < 5; j++) {
|
||||||
pattern[((tiley + j + 1) * total_width) + (tilex + 5)] = tilepat[j];
|
pattern[((tiley + j + 1) * total_width) + (tilex + 5)] = tilepat[j];
|
||||||
}
|
}
|
||||||
@ -1003,12 +1000,14 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si
|
|||||||
pattern[((tiley + j) * total_width) + tilex] = tilepat[j];
|
pattern[((tiley + j) * total_width) + tilex] = tilepat[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("DCC: %d\n", dcc);
|
if (symbol->debug) {
|
||||||
|
printf("DCC: %d\n", dcc);
|
||||||
|
|
||||||
for (i = 0; i < (total_height * total_width); i++) {
|
for (i = 0; i < (total_height * total_width); i++) {
|
||||||
printf("%c", pattern[i]);
|
printf("%c", pattern[i]);
|
||||||
if ((i + 1) % total_width == 0) {
|
if ((i + 1) % total_width == 0) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +267,9 @@ extern "C" {
|
|||||||
#define DM_SQUARE 100
|
#define DM_SQUARE 100
|
||||||
#define DM_DMRE 101
|
#define DM_DMRE 101
|
||||||
|
|
||||||
|
// Ultracode specific option
|
||||||
|
#define ULTRA_COMPRESSION 128
|
||||||
|
|
||||||
// Warning and error conditions
|
// Warning and error conditions
|
||||||
#define ZINT_WARN_INVALID_OPTION 2
|
#define ZINT_WARN_INVALID_OPTION 2
|
||||||
#define ZINT_WARN_USES_ECI 3
|
#define ZINT_WARN_USES_ECI 3
|
||||||
|
@ -37,37 +37,38 @@
|
|||||||
|
|
||||||
/* Print list of supported symbologies */
|
/* Print list of supported symbologies */
|
||||||
void types(void) {
|
void types(void) {
|
||||||
printf( " 1: Code 11 51: Pharma One-Track 92: Aztec Code\n"
|
printf( " 1: Code 11 52: PZN 97: Micro QR Code\n"
|
||||||
" 2: Standard 2of5 52: PZN 93: DAFT Code\n"
|
" 2: Standard 2of5 53: Pharma Two-Track 98: HIBC Code 128\n"
|
||||||
" 3: Interleaved 2of5 53: Pharma Two-Track 97: Micro QR Code\n"
|
" 3: Interleaved 2of5 55: PDF417 99: HIBC Code 39\n"
|
||||||
" 4: IATA 2of5 55: PDF417 98: HIBC Code 128\n"
|
" 4: IATA 2of5 56: PDF417 Trunc 102: HIBC Data Matrix\n"
|
||||||
" 6: Data Logic 56: PDF417 Trunc 99: HIBC Code 39\n"
|
" 6: Data Logic 57: Maxicode 104: HIBC QR Code\n"
|
||||||
" 7: Industrial 2of5 57: Maxicode 102: HIBC Data Matrix\n"
|
" 7: Industrial 2of5 58: QR Code 106: HIBC PDF417\n"
|
||||||
" 8: Code 39 58: QR Code 104: HIBC QR Code\n"
|
" 8: Code 39 60: Code 128-B 108: HIBC MicroPDF417\n"
|
||||||
" 9: Extended Code 39 60: Code 128-B 106: HIBC PDF417\n"
|
" 9: Extended Code 39 63: AP Standard Customer 110: HIBC Codablock-F\n"
|
||||||
"13: EAN 63: AP Standard Customer 108: HIBC MicroPDF417\n"
|
"13: EAN 66: AP Reply Paid 112: HIBC Aztec Code\n"
|
||||||
"14: EAN + Check 66: AP Reply Paid 110: HIBC Codablock-F\n"
|
"14: EAN + Check 67: AP Routing 115: DotCode\n"
|
||||||
"16: GS1-128 67: AP Routing 112: HIBC Aztec Code\n"
|
"16: GS1-128 68: AP Redirection 116: Han Xin Code\n"
|
||||||
"18: Codabar 68: AP Redirection 115: DotCode\n"
|
"18: Codabar 69: ISBN 121: RM Mailmark\n"
|
||||||
"20: Code 128 69: ISBN 116: Han Xin Code\n"
|
"20: Code 128 70: RM4SCC 128: Aztec Runes\n"
|
||||||
"21: Leitcode 70: RM4SCC 121: RM Mailmark\n"
|
"21: Leitcode 71: Data Matrix 129: Code 32\n"
|
||||||
"22: Identcode 71: Data Matrix 128: Aztec Runes\n"
|
"22: Identcode 72: EAN-14 130: Comp EAN\n"
|
||||||
"23: Code 16k 72: EAN-14 129: Code 32\n"
|
"23: Code 16k 73: VIN (North America) 131: Comp GS1-128\n"
|
||||||
"24: Code 49 73: VIN (North America) 130: Comp EAN\n"
|
"24: Code 49 74: Codablock-F 132: Comp DataBar Omni\n"
|
||||||
"25: Code 93 74: Codablock-F 131: Comp GS1-128\n"
|
"25: Code 93 75: NVE-18 133: Comp DataBar Ltd\n"
|
||||||
"28: Flattermarken 75: NVE-18 132: Comp DataBar Omni\n"
|
"28: Flattermarken 76: Japanese Post 134: Comp DataBar ExpOm\n"
|
||||||
"29: GS1 DataBar Omni 76: Japanese Post 133: Comp DataBar Ltd\n"
|
"29: GS1 DataBar Omni 77: Korea Post 135: Comp UPC-A\n"
|
||||||
"30: GS1 DataBar Ltd 77: Korea Post 134: Comp DataBar ExpOm\n"
|
"30: GS1 DataBar Ltd 79: GS1 DataBar Stack 136: Comp UPC-E\n"
|
||||||
"31: GS1 DataBar ExpOm 79: GS1 DataBar Stack 135: Comp UPC-A\n"
|
"31: GS1 DataBar ExpOm 80: GS1 DataBar Stack Omni 137: Comp DataBar Stack\n"
|
||||||
"32: Telepen Alpha 80: GS1 DataBar Stack Omni 136: Comp UPC-E\n"
|
"32: Telepen Alpha 81: GS1 DataBar ESO 138: Comp DataBar Stack Omni\n"
|
||||||
"34: UPC-A 81: GS1 DataBar ESO 137: Comp DataBar Stack\n"
|
"34: UPC-A 82: Planet 1139: Comp DataBar ESO\n"
|
||||||
"35: UPC-A + Check 82: Planet 138: Comp DataBar Stack Omni\n"
|
"35: UPC-A + Check 84: MicroPDF 140: Channel Code\n"
|
||||||
"37: UPC-E 84: MicroPDF 139: Comp DataBar ESO\n"
|
"37: UPC-E 85: USPS OneCode 141: Code One\n"
|
||||||
"38: UPC-E + Check 85: USPS OneCode 140: Channel Code\n"
|
"38: UPC-E + Check 86: UK Plessey 142: Grid Matrix\n"
|
||||||
"40: Postnet 86: UK Plessey 141: Code One\n"
|
"40: Postnet 87: Telepen Numeric 143: UPNQR\n"
|
||||||
"47: MSI Plessey 87: Telepen Numeric 142: Grid Matrix\n"
|
"47: MSI Plessey 89: ITF-14 144: Ultracode\n"
|
||||||
"49: FIM 89: ITF-14 143: UPNQR\n"
|
"49: FIM 90: KIX Code 145: rMQR\n"
|
||||||
"50: Logmars 90: KIX Code 145: rMQR\n"
|
"50: Logmars 92: Aztec Code\n"
|
||||||
|
"51: Pharma One-Track 93: DAFT Code\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user