diff --git a/bench/bench.c b/bench/bench.c index e6fb6351..a374edf9 100644 --- a/bench/bench.c +++ b/bench/bench.c @@ -26,11 +26,13 @@ #include #include +#include #include "bench.h" #include "../src/utils.h" #ifndef _WIN32 +#include #include #else #include @@ -67,7 +69,7 @@ bench_start(struct bench *bench) (void) gettimeofday(&val, NULL); bench->start = (struct bench_time) { .seconds = val.tv_sec, - .microseconds = val.tv_usec, + .nanoseconds = val.tv_usec * 1000, }; } @@ -78,17 +80,43 @@ bench_stop(struct bench *bench) (void) gettimeofday(&val, NULL); bench->stop = (struct bench_time) { .seconds = val.tv_sec, - .microseconds = val.tv_usec, + .nanoseconds = val.tv_usec * 1000, + }; +} + +#ifndef _WIN32 +void +bench_start2(struct bench *bench) +{ + struct timespec t; + (void) clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t); + // (void) clock_gettime(CLOCK_MONOTONIC, &t); + bench->start = (struct bench_time) { + .seconds = t.tv_sec, + .nanoseconds = t.tv_nsec, }; } +void +bench_stop2(struct bench *bench) +{ + struct timespec t; + (void) clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t); + // (void) clock_gettime(CLOCK_MONOTONIC, &t); + bench->stop = (struct bench_time) { + .seconds = t.tv_sec, + .nanoseconds = t.tv_nsec, + }; +} +#endif + void bench_elapsed(const struct bench *bench, struct bench_time *result) { result->seconds = bench->stop.seconds - bench->start.seconds; - result->microseconds = bench->stop.microseconds - bench->start.microseconds; - if (result->microseconds < 0) { - result->microseconds += 1000000; + result->nanoseconds = bench->stop.nanoseconds - bench->start.nanoseconds; + if (result->nanoseconds < 0) { + result->nanoseconds += 1000000000; result->seconds--; } } @@ -101,8 +129,48 @@ bench_elapsed_str(const struct bench *bench) int ret; bench_elapsed(bench, &elapsed); - ret = asprintf(&buf, "%ld.%06ld", elapsed.seconds, elapsed.microseconds); + ret = asprintf(&buf, "%ld.%06ld", elapsed.seconds, elapsed.nanoseconds / 1000); assert(ret >= 0); return buf; } + +/* Utils for bench method adapted from: https://hackage.haskell.org/package/tasty-bench */ + +#define fit(x1, x2) (x1) / 5 + 2 * ((x2) / 5) +#define sqr(x) (x) * (x) + +static void +predict(long long t1, long long t2, struct estimate *est) +{ + const long long t = fit(t1, t2); + est->elapsed = t; + est->stdev = trunc(sqrt((double)sqr(t1 - t) + (double)sqr(t2 - 2 * t))); +} + +#define high(t, prec) t + prec +#define low(t, prec) t - prec +#define MIN_PRECISION 1000000 /* 1ms */ + +void +predictPerturbed(const struct bench_time *b1, const struct bench_time *b2, + struct estimate *est) +{ + const long long t1 = bench_time_elapsed_nanoseconds(b1); + const long long t2 = bench_time_elapsed_nanoseconds(b2); + +#ifndef _WIN32 + struct timespec ts; + (void) clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts); + long long precision = MAX(ts.tv_sec * 1000000000 + ts.tv_nsec, MIN_PRECISION); +#else + long long precision = MIN_PRECISION; +#endif + + struct estimate est1; + struct estimate est2; + predict(t1, t2, est); + predict(low(t1, precision), high(t2, precision), &est1); + predict(high(t1, precision), low(t2, precision), &est2); + est->stdev = MAX(est1.stdev, est2.stdev); +} diff --git a/bench/bench.h b/bench/bench.h index facee3d1..de1ac32b 100644 --- a/bench/bench.h +++ b/bench/bench.h @@ -27,7 +27,7 @@ struct bench_time { long seconds; - long microseconds; + long nanoseconds; }; struct bench { @@ -35,15 +35,75 @@ struct bench { struct bench_time stop; }; +struct estimate { + long long int elapsed; + long long int stdev; +}; + void bench_start(struct bench *bench); void bench_stop(struct bench *bench); +#ifndef _WIN32 +void +bench_start2(struct bench *bench); +void +bench_stop2(struct bench *bench); +#else +/* TODO: implement clock_getres for Windows */ +#define bench_start2 bench_start +#define bench_stop2 bench_stop +#endif + void bench_elapsed(const struct bench *bench, struct bench_time *result); + +#define bench_time_elapsed_microseconds(elapsed) \ + (elapsed)->nanoseconds / 1000 + 1000000 * (elapsed)->seconds +#define bench_time_elapsed_nanoseconds(elapsed) \ + (elapsed)->nanoseconds + 1000000000 * (elapsed)->seconds + /* The caller is responsibile to free() the returned string. */ char * bench_elapsed_str(const struct bench *bench); +/* Bench method adapted from: https://hackage.haskell.org/package/tasty-bench */ +#define BENCH(target_stdev, n, time, est, ...) do { \ + struct bench _bench; \ + struct bench_time _t1; \ + struct bench_time _t2; \ + n = 1; \ + bench_start2(&_bench); \ + do { __VA_ARGS__ } while (0); \ + bench_stop2(&_bench); \ + bench_elapsed(&_bench, &_t1); \ + do { \ + bench_start2(&_bench); \ + for (int k = 0; k < 2 * n; k++) { \ + do { __VA_ARGS__ } while (0); \ + } \ + bench_stop2(&_bench); \ + bench_elapsed(&_bench, &_t2); \ + predictPerturbed(&_t1, &_t2, &est); \ + if (est.stdev < (long long)(MAX(0, target_stdev * (double)est.elapsed))) {\ + scale_estimate(est, n); \ + time = _t2; \ + n *= 2; \ + break; \ + } \ + n *= 2; \ + _t1 = _t2; \ + } while (1); \ +} while (0) + +void +predictPerturbed(const struct bench_time *t1, const struct bench_time *t2, + struct estimate *est); + +#define scale_estimate(est, n) do { \ + est.elapsed /= n; \ + est.stdev /= n; \ +} while (0); + #endif /* LIBXKBCOMMON_BENCH_H */ diff --git a/bench/compile-keymap.c b/bench/compile-keymap.c new file mode 100644 index 00000000..817c7fde --- /dev/null +++ b/bench/compile-keymap.c @@ -0,0 +1,263 @@ +/* + * Copyright © 2024 Pierre Le Marre + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include + +#include "xkbcommon/xkbcommon.h" +#include "utils.h" + +#include "bench.h" + +#define DEFAULT_ITERATIONS 3000 +#define DEFAULT_STDEV 0.05 + +static void +usage(char **argv) +{ + printf("Usage: %s [OPTIONS]\n" + "\n" + "Benchmark compilation of the given RMLVO\n" + "\n" + "Options:\n" + " --help\n" + " Print this help and exit\n" + " --iter\n" + " Exact number of iterations to run\n" + " --stdev\n" + " Minimal relative standard deviation (percentage) to reach.\n" + " (default: %f)\n" + "Note: --iter and --stdev are mutually exclusive.\n" + "\n" + "XKB-specific options:\n" + " --rules \n" + " The XKB ruleset (default: '%s')\n" + " --model \n" + " The XKB model (default: '%s')\n" + " --layout \n" + " The XKB layout (default: '%s')\n" + " --variant \n" + " The XKB layout variant (default: '%s')\n" + " --options \n" + " The XKB options (default: '%s')\n" + "\n", + argv[0], DEFAULT_STDEV * 100, DEFAULT_XKB_RULES, + DEFAULT_XKB_MODEL, DEFAULT_XKB_LAYOUT, + DEFAULT_XKB_VARIANT ? DEFAULT_XKB_VARIANT : "", + DEFAULT_XKB_OPTIONS ? DEFAULT_XKB_OPTIONS : ""); +} + +int +main(int argc, char **argv) +{ + struct xkb_context *context; + struct bench bench; + struct bench_time elapsed; + struct estimate est; + bool explicit_iterations = false; + int ret = 0; + struct xkb_rule_names rmlvo = { + .rules = DEFAULT_XKB_RULES, + .model = DEFAULT_XKB_MODEL, + /* layout and variant are tied together, so we either get user-supplied for + * both or default for both, see below */ + .layout = NULL, + .variant = NULL, + .options = DEFAULT_XKB_OPTIONS, + }; + int max_iterations = DEFAULT_ITERATIONS; + double stdev = DEFAULT_STDEV; + + enum options { + OPT_RULES, + OPT_MODEL, + OPT_LAYOUT, + OPT_VARIANT, + OPT_OPTION, + OPT_ITERATIONS, + OPT_STDEV, + }; + + static struct option opts[] = { + {"help", no_argument, 0, 'h'}, + {"rules", required_argument, 0, OPT_RULES}, + {"model", required_argument, 0, OPT_MODEL}, + {"layout", required_argument, 0, OPT_LAYOUT}, + {"variant", required_argument, 0, OPT_VARIANT}, + {"options", required_argument, 0, OPT_OPTION}, + {"iter", required_argument, 0, OPT_ITERATIONS}, + {"stdev", required_argument, 0, OPT_STDEV}, + {0, 0, 0, 0}, + }; + + while (1) { + int c; + int option_index = 0; + c = getopt_long(argc, argv, "h", opts, &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': + usage(argv); + exit(EXIT_SUCCESS); + case OPT_RULES: + rmlvo.rules = optarg; + break; + case OPT_MODEL: + rmlvo.model = optarg; + break; + case OPT_LAYOUT: + rmlvo.layout = optarg; + break; + case OPT_VARIANT: + rmlvo.variant = optarg; + break; + case OPT_OPTION: + rmlvo.options = optarg; + break; + case OPT_ITERATIONS: + if (max_iterations == 0) { + usage(argv); + exit(EXIT_INVALID_USAGE); + } + max_iterations = atoi(optarg); + if (max_iterations <= 0) + max_iterations = DEFAULT_ITERATIONS; + explicit_iterations = true; + break; + case OPT_STDEV: + if (explicit_iterations) { + usage(argv); + exit(EXIT_INVALID_USAGE); + } + stdev = atof(optarg) / 100; + if (stdev <= 0) + stdev = DEFAULT_STDEV; + max_iterations = 0; + break; + default: + usage(argv); + exit(EXIT_INVALID_USAGE); + } + } + + /* Now fill in the layout */ + if (!rmlvo.layout || !*rmlvo.layout) { + if (rmlvo.variant && *rmlvo.variant) { + fprintf(stderr, "Error: a variant requires a layout\n"); + return EXIT_INVALID_USAGE; + } + rmlvo.layout = DEFAULT_XKB_LAYOUT; + rmlvo.variant = DEFAULT_XKB_VARIANT; + } + + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) + exit(1); + + struct xkb_keymap *keymap; + char *keymap_str; + + keymap = xkb_keymap_new_from_names(context, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + fprintf(stderr, "ERROR: Cannot compile keymap.\n"); + goto keymap_error; + exit(1); + } + keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); + xkb_keymap_unref(keymap); + + /* Suspend stdout and stderr outputs */ + fflush(stdout); + int stdout_old = dup(STDOUT_FILENO); + int stdout_new = open("/dev/null", O_WRONLY); + dup2(stdout_new, STDOUT_FILENO); + close(stdout_new); + fflush(stderr); + int stderr_old = dup(STDERR_FILENO); + int stderr_new = open("/dev/null", O_WRONLY); + dup2(stderr_new, STDERR_FILENO); + close(stderr_new); + + if (explicit_iterations) { + stdev = 0; + bench_start2(&bench); + for (int i = 0; i < max_iterations; i++) { + keymap = xkb_keymap_new_from_string( + context, keymap_str, + XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + assert(keymap); + xkb_keymap_unref(keymap); + } + bench_stop2(&bench); + + bench_elapsed(&bench, &elapsed); + est.elapsed = (bench_time_elapsed_nanoseconds(&elapsed)) / max_iterations; + est.stdev = 0; + } else { + bench_start2(&bench); + BENCH(stdev, max_iterations, elapsed, est, + keymap = xkb_keymap_new_from_string( + context, keymap_str, + XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + assert(keymap); + xkb_keymap_unref(keymap); + ); + bench_stop2(&bench); + } + + /* Restore stdout and stderr outputs */ + fflush(stdout); + dup2(stdout_old, STDOUT_FILENO); + close(stdout_old); + fflush(stderr); + dup2(stderr_old, STDERR_FILENO); + close(stderr_old); + + free(keymap_str); + + struct bench_time total_elapsed; + bench_elapsed(&bench, &total_elapsed); + if (explicit_iterations) { + fprintf(stderr, + "mean: %lld µs; compiled %d keymaps in %ld.%06lds\n", + est.elapsed / 1000, max_iterations, + total_elapsed.seconds, total_elapsed.nanoseconds / 1000); + } else { + fprintf(stderr, + "mean: %lld µs; stdev: %f%% (target: %f%%); " + "last run: compiled %d keymaps in %ld.%06lds; " + "total time: %ld.%06lds\n", + est.elapsed / 1000, est.stdev * 100.0 / est.elapsed, stdev * 100, + max_iterations, elapsed.seconds, elapsed.nanoseconds / 1000, + total_elapsed.seconds, total_elapsed.nanoseconds / 1000); + } + +keymap_error: + xkb_context_unref(context); + return ret; +} diff --git a/changes/api/+deprecated-keysyms-warning.feature.md b/changes/api/+deprecated-keysyms-warning.feature.md new file mode 100644 index 00000000..a2aa1ddf --- /dev/null +++ b/changes/api/+deprecated-keysyms-warning.feature.md @@ -0,0 +1,8 @@ +Added deprecated keysym warnings: +- *name* deprecation (typo, historical alias), reporting the reference name; +- *keysym* deprecation (ambiguous meaning, all names deprecated). + +These warnings are activated by setting the log verbosity to at least 2. + +It is advised to fix these warnings, as the deprecated items may be removed in a +future release. diff --git a/doc/message-registry.md b/doc/message-registry.md index 0a518932..8bf15aa8 100644 --- a/doc/message-registry.md +++ b/doc/message-registry.md @@ -6,7 +6,7 @@ NOTE: This file has been generated automatically by “update-message-registry.p --> This page lists the warnings and errors generated by xkbcommon. -There are currently 55 entries. +There are currently 57 entries. @todo The documentation of the log messages is a work in progress. @@ -34,6 +34,8 @@ There are currently 55 entries. | [XKB-254] | `invalid-set-default-statement` | Invalid statement setting default values | Error | | [XKB-266] | `conflicting-key-type-map-entry` | Conflicting “map” entries in type definition | Warning | | [XKB-286] | `undefined-key-type` | Warn if using an undefined key type | Warning | +| [XKB-301] | `deprecated-keysym` | A keysym has been deprecated: consider using an alternative keysym | Warning | +| [XKB-302] | `deprecated-keysym-name` | A keysym name has been deprecated: use the corresponding canonical name instead | Warning | | [XKB-305] | `non-base-group-name` | Warn if a group name was defined for group other than the first one | Warning | | [XKB-312] | `unsupported-shift-level` | Warn when a shift level is not supported | Error | | [XKB-338] | `included-file-not-found` | Could not find a file used in an include statement | Error | @@ -284,6 +286,31 @@ xkbcommon supports group index in the range (1..4).
Summary
Warn if using an undefined key type
+### XKB-301 – Deprecated keysym {#XKB-301} + +
+
Since
1.8.0
+
Type
Warning
+
Summary
A keysym has been deprecated: consider using an alternative keysym
+
+ +Some keysyms have ambiguous meaning. It is advised to migrate to an alternative keysym +if possible, as deprecated keysyms may be removed in the future. Consider using Unicode +keysyms (`Unnnn`) if relevant. + + +### XKB-302 – Deprecated keysym name {#XKB-302} + +
+
Since
1.8.0
+
Type
Warning
+
Summary
A keysym name has been deprecated: use the corresponding canonical name instead
+
+ +Some keysym names have typos, unconventional names or historical aliases of a reference name. +Please consider migrating to the reference name reported in the warning message. + + ### XKB-305 – Non base group name {#XKB-305}
@@ -705,6 +732,8 @@ The modifiers used in `map` or `preserve` entries should be declared using the e [XKB-254]: @ref XKB-254 [XKB-266]: @ref XKB-266 [XKB-286]: @ref XKB-286 +[XKB-301]: @ref XKB-301 +[XKB-302]: @ref XKB-302 [XKB-305]: @ref XKB-305 [XKB-312]: @ref XKB-312 [XKB-338]: @ref XKB-338 diff --git a/doc/message-registry.yaml b/doc/message-registry.yaml index 6a9725fd..7445aafc 100644 --- a/doc/message-registry.yaml +++ b/doc/message-registry.yaml @@ -152,6 +152,23 @@ added: ALWAYS type: warning description: "Warn if using an undefined key type" +- id: "deprecated-keysym" + code: 301 + added: 1.8.0 + type: warning + description: "A keysym has been deprecated: consider using an alternative keysym" + details: | + Some keysyms have ambiguous meaning. It is advised to migrate to an alternative keysym + if possible, as deprecated keysyms may be removed in the future. Consider using Unicode + keysyms (`Unnnn`) if relevant. +- id: "deprecated-keysym-name" + code: 302 + added: 1.8.0 + type: warning + description: "A keysym name has been deprecated: use the corresponding canonical name instead" + details: | + Some keysym names have typos, unconventional names or are historical aliases. + Please consider migrating to the reference name reported in the warning message. - id: "non-base-group-name" code: 305 added: ALWAYS @@ -410,5 +427,4 @@ The modifiers used in `map` or `preserve` entries should be declared using the entry `modifiers` in the key type. -# TODO: deprecated keysym # TODO: unicode keysym when named and recommended keysym exists diff --git a/meson.build b/meson.build index ff3a731d..b0ae2e7b 100644 --- a/meson.build +++ b/meson.build @@ -648,6 +648,7 @@ test_configh_data = configuration_data() test_configh_data.set_quoted('TEST_XKB_CONFIG_ROOT', meson.current_source_dir()/'test'/'data') configure_file(output: 'test-config.h', configuration: test_configh_data) +m_dep = cc.find_library('m', required : false) # Some tests need to use unexported symbols, so we link them against # an internal copy of libxkbcommon with all symbols exposed. libxkbcommon_test_internal = static_library( @@ -660,6 +661,7 @@ libxkbcommon_test_internal = static_library( libxkbcommon_sources, include_directories: include_directories('src', 'include'), c_args: ['-DENABLE_PRIVATE_APIS'], + dependencies: [m_dep], ) test_dep = declare_dependency( include_directories: include_directories('src', 'include'), @@ -910,6 +912,17 @@ benchmark( executable('bench-rulescomp', 'bench/rulescomp.c', dependencies: test_dep), env: bench_env, ) +if cc.has_header_symbol('getopt.h', 'getopt_long', prefix: '#define _GNU_SOURCE') + benchmark( + 'compile-keymap', + executable( + 'bench-compile-keymap', + 'bench/compile-keymap.c', + dependencies: test_dep + ), + env: bench_env, + ) +endif benchmark( 'compose', executable('bench-compose', 'bench/compose.c', dependencies: test_dep), diff --git a/scripts/makeheader b/scripts/makeheader index 7091aa48..52ad162f 100755 --- a/scripts/makeheader +++ b/scripts/makeheader @@ -129,5 +129,5 @@ for path in HEADERS: line = keysym_entry_pattern.sub(make_keysym_entry, line) line = xorgproto_keysym_prefix_pattern.sub(r"XKB_KEY_\1", line) - print(line, end="") + print(line.rstrip(), end="\n") print("\n\n#endif") diff --git a/scripts/makekeys b/scripts/makekeys index 9c822137..e0b27222 100755 --- a/scripts/makekeys +++ b/scripts/makekeys @@ -1,14 +1,90 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 +import itertools +import random import re import sys -import itertools +from collections import defaultdict +from dataclasses import dataclass +from enum import Enum +from pathlib import Path +from typing import DefaultDict, Generator, Iterable, Iterator import perfect_hash -pattern = re.compile(r"^#define\s+XKB_KEY_(?P\w+)\s+(?P0x[0-9a-fA-F]+)\s") -matches = [pattern.match(line) for line in open(sys.argv[1])] -entries = [(m.group("name"), int(m.group("value"), 16)) for m in matches if m] +# Set the seed explicitly, so we reduce diff +random.seed(b"libxkbcommon") + +KEYSYM_ENTRY_PATTERN = re.compile( + r""" + ^\#define\s+ + XKB_KEY_(?P\w+)\s+ + (?P0x[0-9a-fA-F]+)\s* + (?:/\*\s* + (?: + (?Pdeprecated)| + \([0-9a-fA-F]{4,}>)\)| + \(U\+(?P[0-9a-fA-F]{4,})\s(?:\s|\w|-)+\)| + .* + ) + )? + """, + re.VERBOSE, +) + + +class Deprecation(Enum): + NONE = "none" + "No deprecation" + EXPLICIT = "explicit" + "Explicit deprecation in comment: /* deprecated */" + IMPLICIT = "implicit" + """ + Implicit deprecation: the keysym has already been defined with a previous + name, and the present name has not been declared explicitly as an alias. + """ + + +@dataclass +class Keysym: + name: str + value: int + deprecated: Deprecation + alias: bool + + +def parse_keysyms(path: Path) -> Iterator[Keysym]: + with path.open("rt", encoding="utf-8") as fd: + for line in fd: + if m := KEYSYM_ENTRY_PATTERN.match(line): + yield Keysym( + name=m.group("name"), + value=int(m.group("value"), 16), + deprecated=Deprecation.EXPLICIT + if m.group("deprecated") or m.group("deprecated_unicode") + else Deprecation.NONE, + alias="alias for" in line.casefold() + or m.group("unicode_alt_semantics"), + ) + + +def get_keysyms(path: Path) -> dict[int, list[Keysym]]: + keysyms: DefaultDict[int, list[Keysym]] = defaultdict(list) + for keysym in parse_keysyms(path): + if ( + (ks := keysyms.get(keysym.value)) + and keysym.deprecated is Deprecation.NONE + and not keysym.alias + # deal with first name being deprecated + and any(k.deprecated is Deprecation.NONE for k in ks) + ): + keysym.deprecated = Deprecation.IMPLICIT + keysyms[keysym.value].append(keysym) + return keysyms + + +keysyms_by_value = get_keysyms(Path(sys.argv[1])) +entries = tuple(itertools.chain.from_iterable(keysyms_by_value.values())) # Sort based on the keysym name: # 1. Sort by the casefolded name: e.g. kana_ya < kana_YO. @@ -17,10 +93,10 @@ entries = [(m.group("name"), int(m.group("value"), 16)) for m in matches if m] # E.g. kana_YA < kana_ya < kana_YO < kana_yo # WARNING: this sort must not be changed, as some functions e.g. # xkb_keysym_from_name rely on upper case variant occuring first. -entries_isorted = sorted(entries, key=lambda e: (e[0].casefold(), e[0])) +entries_isorted = sorted(entries, key=lambda e: (e.name.casefold(), e.name)) # Sort based on keysym value. Sort is stable so in case of duplicate, the first # keysym occurence stays first. -entries_kssorted = sorted(entries, key=lambda e: e[1]) +entries_kssorted = sorted(entries, key=lambda e: e.value) print( """ @@ -32,10 +108,22 @@ print( """ ) -entry_offsets = {} +entry_offsets: dict[str, int] = {} +UINT16_MAX = (1 << 16) - 1 +DEPRECATED_KEYSYM = UINT16_MAX +MAX_EXPLICIT_DEPRECATED_ALIAS_INDEX_LOG2 = 8 +MAX_EXPLICIT_DEPRECATED_ALIAS_INDEX = 1 << MAX_EXPLICIT_DEPRECATED_ALIAS_INDEX_LOG2 +MAX_EXPLICIT_DEPRECATED_ALIAS_COUNT_LOG2 = 4 +MAX_EXPLICIT_DEPRECATED_ALIAS_COUNT = 1 << MAX_EXPLICIT_DEPRECATED_ALIAS_COUNT_LOG2 +MAX_OFFSET = DEPRECATED_KEYSYM - 1 print( """ +#include +#include + +#include "xkbcommon/xkbcommon.h" + #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverlength-strings" @@ -44,10 +132,12 @@ static const char *keysym_names = """.strip() ) offs = 0 -for name, _ in entries_isorted: - entry_offsets[name] = offs - print(' "{name}\\0"'.format(name=name)) - offs += len(name) + 1 +for keysym in entries_isorted: + if offs >= MAX_OFFSET: + raise ValueError(f"Offset must be kept under {MAX_OFFSET}, got: {offs}.") + entry_offsets[keysym.name] = offs + print(f' "{keysym.name}\\0"') + offs += len(keysym.name) + 1 print( """ ; @@ -57,7 +147,6 @@ print( """.strip() ) - template = r""" static const uint16_t keysym_name_G[] = { $G @@ -83,7 +172,7 @@ keysym_name_perfect_hash(const char *key) """ print( perfect_hash.generate_code( - keys=[name for name, value in entries_isorted], + keys=[keysym.name for keysym in entries_isorted], template=template, ) ) @@ -92,16 +181,16 @@ print( """ struct name_keysym { xkb_keysym_t keysym; - uint32_t offset; + uint16_t offset; };\n""" ) -def print_entries(x): - for name, value in x: +def print_entries(entries: Iterable[Keysym]): + for entry in entries: print( " {{ 0x{value:08x}, {offs} }}, /* {name} */".format( - offs=entry_offsets[name], value=value, name=name + offs=entry_offsets[entry.name], value=entry.value, name=entry.name ) ) @@ -113,6 +202,122 @@ print("};\n") # *.sort() is stable so we always get the first keysym for duplicate print("static const struct name_keysym keysym_to_name[] = {") print_entries( - next(g[1]) for g in itertools.groupby(entries_kssorted, key=lambda e: e[1]) + next(g[1]) for g in itertools.groupby(entries_kssorted, key=lambda e: e.value) ) +print("};\n") + + +def make_deprecated_entry( + value, + keysyms: list[Keysym], + entry_offsets: dict[str, int], + explicit_deprecated_aliases_index: int, +) -> tuple[str | None, tuple[int, ...]]: + assert keysyms + non_deprecated_ks = tuple(k for k in keysyms if k.deprecated is Deprecation.NONE) + explicit_deprecated_aliases: tuple[int, ...] = () + if non_deprecated_ks: + # Keysym is not deprecated. Check if none of its aliases are. + if len(keysyms) == 1 or all( + ks.alias and ks.deprecated is Deprecation.NONE for ks in keysyms[1:] + ): + return None, () + ref = non_deprecated_ks[0].name + canonical_name = f"Reference: {ref}. " + assert ref in entry_offsets + canonical_index = str(entry_offsets[ref]) + deprecated_ks = tuple(k for k in keysyms if k not in non_deprecated_ks) + if any(ks.alias and ks.deprecated is Deprecation.NONE for ks in keysyms[1:]): + # keysym has both explicit and deprecated aliases + explicit_deprecated_aliases = tuple( + entry_offsets[ks.name] + for ks in keysyms[1:] + if ks.deprecated is not Deprecation.NONE + ) + assert ( + explicit_deprecated_aliases_index < MAX_EXPLICIT_DEPRECATED_ALIAS_INDEX + ) + assert ( + len(explicit_deprecated_aliases) < MAX_EXPLICIT_DEPRECATED_ALIAS_COUNT + ) + else: + explicit_deprecated_aliases_index = 0 + else: + # Keysym is deprecated + canonical_name = "" + canonical_index = "DEPRECATED_KEYSYM" + deprecated_ks = keysyms + explicit_deprecated_aliases_index = 0 + if non_deprecated_ks[1:]: + non_deprecated = ( + "Non deprecated aliases: " + + ", ".join(ks.name for ks in non_deprecated_ks[1:]) + + ". " + ) + else: + non_deprecated = "" + deprecated = ", ".join(ks.name for ks in deprecated_ks) + comment = f"{canonical_name}{non_deprecated}Deprecated: {deprecated}" + return ( + f" {{ 0x{value:0>8x}, {canonical_index: <17}, {explicit_deprecated_aliases_index}, {len(explicit_deprecated_aliases)} }}, /* {comment} */", + explicit_deprecated_aliases, + ) + + +def generate_deprecated_keysyms( + keysyms_by_value: dict[int, list[Keysym]], entry_offsets: dict[str, int] +) -> Generator[tuple[int, ...], None, None]: + explicit_deprecated_aliases_index = 0 + for value, keysyms in sorted(keysyms_by_value.items(), key=lambda e: e[0]): + assert keysyms + c_entry, explicit_deprecated_aliases = make_deprecated_entry( + value, keysyms, entry_offsets, explicit_deprecated_aliases_index + ) + if c_entry is not None: + print(c_entry) + if explicit_deprecated_aliases: + yield explicit_deprecated_aliases + explicit_deprecated_aliases_index += len(explicit_deprecated_aliases) + + +def generate_mixed_aliases(aliases: Iterable[Iterable[int]]): + for xs in aliases: + for x in xs: + print(f" {x},") + + +print(f"#define DEPRECATED_KEYSYM 0x{DEPRECATED_KEYSYM:x}") +# NOTE: Alternative implementation, useful the day the indexes do not fit uint16_t. +# print(f""" +# struct deprecated_keysym {{ +# xkb_keysym_t keysym; +# union {{ +# uint32_t offset; +# struct {{ +# uint32_t offset:{MAX_OFFSET_LOG2}; +# /* Explicit deprecated aliases start index & count */ +# uint8_t explicit_index:{MAX_EXPLICIT_DEPRECATED_ALIAS_INDEX_LOG2}; +# uint8_t explicit_count:{MAX_EXPLICIT_DEPRECATED_ALIAS_COUNT_LOG2}; +# }} details; +# }}; +# }}; +# """) +print(""" +struct deprecated_keysym { + xkb_keysym_t keysym; + uint16_t offset; + /* Explicit deprecated aliases start index & count */ + uint8_t explicit_index; + uint8_t explicit_count; +}; +""") +print("static const struct deprecated_keysym deprecated_keysyms[] = {") +explicit_deprecated_aliases = tuple( + generate_deprecated_keysyms(keysyms_by_value, entry_offsets) +) +print("};\n") +print("static const uint32_t explicit_deprecated_aliases[] = {") +generate_mixed_aliases(explicit_deprecated_aliases) print("};") + +print(f"max name offset: {max(entry_offsets.values())}", file=sys.stderr) diff --git a/scripts/update-message-registry.py b/scripts/update-message-registry.py index 402835bb..93e656fd 100755 --- a/scripts/update-message-registry.py +++ b/scripts/update-message-registry.py @@ -3,10 +3,10 @@ from __future__ import annotations import argparse +import re from dataclasses import astuple, dataclass from pathlib import Path -import re -from typing import Callable, Generic, Sequence, TypeVar +from typing import Any, Callable, ClassVar, Generic, Sequence, TypeVar import jinja2 import yaml @@ -16,14 +16,14 @@ class Version: """A semantic version number: MAJOR.MINOR.PATCH.""" - UNKNOWN_VERSION = "ALWAYS" - DEFAULT_VERSION = "1.0.0" + UNKNOWN_VERSION: ClassVar[str] = "ALWAYS" + DEFAULT_VERSION: ClassVar[str] = "1.0.0" major: int minor: int patch: int = 0 - def __str__(self): + def __str__(self) -> str: return ".".join(map(str, astuple(self))) @classmethod @@ -47,7 +47,7 @@ class Example: after: str | None @classmethod - def parse(cls, entry) -> Example: + def parse(cls, entry: Any) -> Example: name = entry.get("name") assert name, entry @@ -89,7 +89,7 @@ class Entry: """ @classmethod - def parse(cls, entry) -> Entry: + def parse(cls, entry: Any) -> Entry: code = entry.get("code") assert code is not None and isinstance(code, int) and code > 0, entry @@ -140,7 +140,7 @@ def message_code_constant(self: Entry) -> str: return f"XKB_{self.type.upper()}_{id}" @property - def message_name(self: Entry): + def message_name(self: Entry) -> str: """Format the message string identifier for display""" return self.id.replace("-", " ").capitalize() @@ -184,7 +184,7 @@ def generate( root: Path, file: Path, skip_removed: bool = False, -): +) -> None: """Generate a file from its Jinja2 template and the message registry""" template_path = file.with_suffix(f"{file.suffix}.jinja") template = env.get_template(str(template_path)) @@ -205,7 +205,7 @@ def generate( @dataclass class Constant(Generic[T]): name: str - pattern: re.Pattern + pattern: re.Pattern[str] conversion: Callable[[str], T] @@ -246,7 +246,11 @@ def read_constants(path: Path, patterns: Sequence[Constant[T]]) -> dict[str, T]: # Read some constants from libxkbcommon that we need constants = read_constants( Path(__file__).parent.parent / "src" / "keymap.h", - (Constant("XKB_MAX_GROUPS", re.compile("^#define\s+XKB_MAX_GROUPS\s+(\d+)"), int),), + ( + Constant( + "XKB_MAX_GROUPS", re.compile(r"^#define\s+XKB_MAX_GROUPS\s+(\d+)"), int + ), + ), ) # Configure Jinja diff --git a/src/compose/parser.c b/src/compose/parser.c index 7b677316..cae80c0f 100644 --- a/src/compose/parser.c +++ b/src/compose/parser.c @@ -62,6 +62,7 @@ OR PERFORMANCE OF THIS SOFTWARE. #include "paths.h" #include "utf8.h" #include "parser.h" +#include "keysym.h" /* * Grammar adapted from libX11/modules/im/ximcp/imLcPrs.c. @@ -630,6 +631,8 @@ parse(struct xkb_compose_table *table, struct scanner *s, val.string.str); goto error; } + check_deprecated_keysyms(scanner_warn_with_code, s, s->ctx, + keysym, val.string.str, val.string.str, "%s", "\n"); if (production.len + 1 > MAX_LHS_LEN) { scanner_warn(s, "too many keysyms (%d) on left-hand side; skipping line", MAX_LHS_LEN + 1); @@ -703,6 +706,8 @@ lhs_mod_list_tok: { val.string.str); goto error; } + check_deprecated_keysyms(scanner_warn_with_code, s, s->ctx, + keysym, val.string.str, val.string.str, "%s", "\n"); if (production.has_keysym) { scanner_warn(s, "right-hand side can have at most one keysym; skipping line"); goto skip; diff --git a/src/keysym.c b/src/keysym.c index ca5640a7..12014a17 100644 --- a/src/keysym.c +++ b/src/keysym.c @@ -85,10 +85,12 @@ find_keysym_index(xkb_keysym_t ks) return -1; } +#define get_name_by_index(index) keysym_names + index + static inline const char * get_name(const struct name_keysym *entry) { - return keysym_names + entry->offset; + return get_name_by_index(entry->offset); } /* Unnamed Unicode codepoint. */ @@ -325,9 +327,7 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags) return (xkb_keysym_t) val | XKB_KEYSYM_UNICODE_OFFSET; } else if (name[0] == '0' && (name[1] == 'x' || (icase && name[1] == 'X'))) { - if (!parse_keysym_hex(&name[2], &val)) - return XKB_KEY_NoSymbol; - if (val > XKB_KEYSYM_MAX) + if (!parse_keysym_hex(&name[2], &val) || val > XKB_KEYSYM_MAX) return XKB_KEY_NoSymbol; return (xkb_keysym_t) val; } @@ -350,6 +350,75 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags) return XKB_KEY_NoSymbol; } +/* + * Check whether a keysym with code "keysym" and name "name" is deprecated. + * • If the keysym is not deprecated itself and has no deprecated names, + * then return false and write NULL in "reference_name". + * • If there is a non-deprecated name for the given keysym, then write this + * name in "reference_name", else write NULL and return true. + * • If "name" is NULL, then returns false: the keysym itself is not deprecated. + * • If "name" is not NULL, then check if "name" is deprecated. + * + * WARNING: this function is unsafe because it does not test if "name" is + * actually a correct name for "keysym". It is intended to be used just after + * keysym resolution. + */ +bool +xkb_keysym_is_deprecated(xkb_keysym_t keysym, + const char *name, + const char **reference_name) +{ + if (keysym > XKB_KEYSYM_MAX) { + /* Invalid keysym */ + *reference_name = NULL; + return false; + } + /* [WARNING] We do not check that name, if defined, is a valid for keysym */ + + int32_t lo = 0, hi = ARRAY_SIZE(deprecated_keysyms) - 1; + while (hi >= lo) { + int32_t mid = (lo + hi) / 2; + if (keysym > deprecated_keysyms[mid].keysym) { + lo = mid + 1; + } else if (keysym < deprecated_keysyms[mid].keysym) { + hi = mid - 1; + } else { + /* Keysym have some deprecated names */ + if (deprecated_keysyms[mid].offset == DEPRECATED_KEYSYM) { + /* All names are deprecated */ + *reference_name = NULL; + return true; + } + /* There is a reference name that is not deprecated */ + *reference_name = get_name_by_index(deprecated_keysyms[mid].offset); + if (name == NULL) + /* No name to check: indicate not deprecated */ + return false; + if (deprecated_keysyms[mid].explicit_count) { + /* Only some explicit names are deprecated */ + uint8_t k = deprecated_keysyms[mid].explicit_index; + const uint8_t k_max = deprecated_keysyms[mid].explicit_index + + deprecated_keysyms[mid].explicit_count; + /* Check every deprecated alias */ + for (; k < k_max; k++) { + const char *alias = + get_name_by_index(explicit_deprecated_aliases[k]); + if (strcmp(name, alias) == 0) + return true; + } + return false; + } else { + /* All names but the reference one are deprecated */ + return strcmp(name, *reference_name) != 0; + } + } + } + + /* Keysym has no deprecated names */ + *reference_name = NULL; + return false; +} + bool xkb_keysym_is_keypad(xkb_keysym_t keysym) { diff --git a/src/keysym.h b/src/keysym.h index 76b3f89b..d567c473 100644 --- a/src/keysym.h +++ b/src/keysym.h @@ -112,6 +112,27 @@ xkb_keysym_iterator_get_name(struct xkb_keysym_iterator *iter, bool xkb_keysym_iterator_is_explicitly_named(struct xkb_keysym_iterator *iter); +bool +xkb_keysym_is_deprecated(xkb_keysym_t keysym, + const char *name, + const char **reference_name); + +#define XKB_MIN_VERBOSITY_DEPRECATED_KEYSYM 2 +#define check_deprecated_keysyms(log_func, log_param, ctx, keysym, name, token, format, end) \ + if (unlikely((ctx)->log_verbosity >= XKB_MIN_VERBOSITY_DEPRECATED_KEYSYM)) { \ + const char *ref_name = NULL; \ + if (xkb_keysym_is_deprecated(keysym, name, &ref_name)) { \ + if (ref_name == NULL) \ + log_func(log_param, XKB_WARNING_DEPRECATED_KEYSYM, \ + "deprecated keysym \"" format "\"." end, token); \ + else \ + log_func(log_param, XKB_WARNING_DEPRECATED_KEYSYM_NAME, \ + "deprecated keysym name \"" format "\"; " \ + "please use \"%s\" instead." end, \ + token, ref_name); \ + } \ + } + bool xkb_keysym_is_lower(xkb_keysym_t keysym); diff --git a/src/keysym.h.jinja b/src/keysym.h.jinja index 190ab78a..0504a520 100644 --- a/src/keysym.h.jinja +++ b/src/keysym.h.jinja @@ -112,6 +112,27 @@ xkb_keysym_iterator_get_name(struct xkb_keysym_iterator *iter, bool xkb_keysym_iterator_is_explicitly_named(struct xkb_keysym_iterator *iter); +bool +xkb_keysym_is_deprecated(xkb_keysym_t keysym, + const char *name, + const char **reference_name); + +#define XKB_MIN_VERBOSITY_DEPRECATED_KEYSYM 2 +#define check_deprecated_keysyms(log_func, log_param, ctx, keysym, name, token, format, end) \ + if (unlikely((ctx)->log_verbosity >= XKB_MIN_VERBOSITY_DEPRECATED_KEYSYM)) { \ + const char *ref_name = NULL; \ + if (xkb_keysym_is_deprecated(keysym, name, &ref_name)) { \ + if (ref_name == NULL) \ + log_func(log_param, XKB_WARNING_DEPRECATED_KEYSYM, \ + "deprecated keysym \"" format "\"." end, token); \ + else \ + log_func(log_param, XKB_WARNING_DEPRECATED_KEYSYM_NAME, \ + "deprecated keysym name \"" format "\"; " \ + "please use \"%s\" instead." end, \ + token, ref_name); \ + } \ + } + bool xkb_keysym_is_lower(xkb_keysym_t keysym); diff --git a/src/ks_tables.h b/src/ks_tables.h index e1db2e39..d97369d4 100644 --- a/src/ks_tables.h +++ b/src/ks_tables.h @@ -5,6 +5,11 @@ * https://raw.github.com/xkbcommon/libxkbcommon/master/src/ks_tables.h */ +#include +#include + +#include "xkbcommon/xkbcommon.h" + #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverlength-strings" @@ -2592,303 +2597,304 @@ static const char *keysym_names = #endif static const uint16_t keysym_name_G[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 4375, 0, 0, 0, 3768, 0, 0, 0, 0, 4202, 0, 0, 0, 0, - 3552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2989, 0, 3202, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 934, 0, 0, 0, 0, 0, 2264, 0, 604, 2271, 0, 0, 2135, 0, - 0, 0, 0, 0, 0, 2468, 0, 1297, 0, 0, 0, 827, 0, 0, 0, 0, 0, 0, 0, 0, - 3935, 1923, 0, 4506, 0, 0, 0, 0, 0, 0, 0, 0, 340, 0, 0, 0, 3519, 0, 0, - 0, 0, 2258, 0, 3583, 0, 0, 0, 0, 0, 0, 1572, 0, 0, 0, 0, 4453, 0, 0, 0, - 0, 0, 868, 0, 0, 0, 1868, 0, 0, 0, 4290, 0, 0, 0, 2508, 0, 0, 201, 0, - 1799, 0, 0, 0, 0, 1087, 0, 0, 0, 0, 3183, 0, 0, 652, 2584, 0, 44, 0, - 1789, 1060, 540, 150, 0, 0, 0, 1772, 0, 77, 1463, 0, 2264, 0, 0, 0, - 1331, 802, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4071, 0, 0, 0, 0, - 0, 2765, 4006, 0, 0, 0, 861, 0, 2402, 0, 0, 3453, 0, 0, 0, 0, 0, 1085, - 0, 4320, 0, 0, 0, 2167, 0, 0, 2715, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, - 1204, 0, 3360, 544, 0, 2978, 0, 0, 0, 1627, 0, 1620, 1663, 1863, 0, 0, - 1305, 0, 0, 0, 3511, 2621, 0, 582, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1504, 0, 0, 0, 0, 3372, 3281, 0, 0, 2610, 0, 0, 442, 0, 2511, 0, - 2910, 0, 0, 2664, 846, 0, 0, 0, 1189, 0, 0, 2961, 1757, 0, 0, 2485, - 1865, 0, 0, 824, 0, 0, 0, 2717, 3476, 0, 1299, 0, 0, 446, 3124, 3885, - 1015, 0, 0, 0, 2080, 0, 239, 3460, 4077, 0, 0, 0, 0, 1820, 0, 0, 0, - 4346, 0, 0, 4455, 0, 0, 0, 0, 2005, 0, 0, 4490, 743, 195, 0, 0, 0, 0, - 0, 3071, 0, 0, 0, 552, 0, 782, 0, 0, 1105, 2541, 0, 0, 0, 2609, 0, 0, - 2720, 1067, 0, 1596, 0, 0, 2627, 0, 0, 0, 0, 1283, 0, 1975, 0, 4202, 0, - 0, 0, 2284, 3274, 194, 0, 0, 14, 0, 0, 2327, 0, 0, 3422, 1106, 0, 4496, - 0, 0, 3184, 0, 309, 2958, 0, 0, 2118, 0, 0, 0, 74, 512, 0, 1471, 3978, - 496, 0, 1655, 1657, 0, 0, 4335, 0, 0, 0, 1658, 0, 2758, 15, 349, 119, - 2748, 1184, 1897, 0, 3416, 0, 0, 284, 0, 0, 0, 0, 0, 1052, 2112, 583, - 0, 1402, 0, 0, 2836, 161, 0, 0, 0, 2399, 0, 0, 0, 536, 2361, 0, 0, 0, - 793, 0, 455, 4332, 2077, 0, 1656, 1460, 2309, 4614, 0, 2252, 128, 0, - 3403, 0, 649, 0, 3947, 0, 0, 0, 0, 0, 4500, 0, 2762, 869, 0, 0, 0, 0, - 0, 118, 0, 0, 0, 2045, 1360, 1951, 0, 1020, 0, 0, 0, 2486, 0, 0, 0, - 4211, 1326, 2569, 0, 0, 0, 2374, 0, 0, 0, 0, 2463, 1947, 0, 0, 175, 0, - 0, 2527, 0, 1720, 797, 0, 0, 0, 2243, 0, 0, 2261, 3020, 0, 0, 0, 409, - 3798, 2752, 0, 0, 0, 2329, 0, 0, 2388, 0, 2596, 0, 3296, 0, 0, 0, 0, - 1632, 0, 0, 1503, 0, 2155, 0, 0, 0, 44, 1383, 0, 760, 600, 508, 0, 0, - 3742, 0, 4205, 1161, 0, 4320, 0, 0, 1678, 3404, 1299, 0, 0, 0, 0, 760, - 0, 1199, 0, 3264, 0, 0, 0, 0, 0, 0, 2258, 0, 0, 2852, 0, 1506, 0, 0, 0, - 0, 1666, 0, 2560, 0, 0, 1065, 4493, 0, 0, 0, 0, 800, 1492, 779, 1935, - 0, 0, 0, 0, 578, 0, 481, 0, 0, 0, 0, 1324, 593, 0, 1053, 191, 1937, - 3402, 0, 0, 0, 151, 2956, 2987, 2190, 3594, 299, 1675, 1430, 0, 1802, - 71, 0, 0, 0, 949, 0, 163, 633, 0, 4063, 0, 0, 0, 0, 0, 0, 4587, 4144, - 170, 517, 3565, 0, 1794, 0, 1708, 0, 1519, 0, 0, 592, 4311, 0, 0, 2087, - 0, 3512, 0, 2064, 1918, 979, 0, 4255, 3531, 3804, 0, 0, 0, 163, 0, 0, - 0, 1762, 971, 3984, 3382, 0, 2434, 0, 0, 0, 3829, 0, 1349, 0, 0, 0, - 1470, 0, 949, 2297, 1266, 0, 0, 0, 0, 0, 1198, 0, 1108, 0, 0, 106, 0, - 0, 0, 0, 0, 0, 1642, 0, 727, 0, 4255, 1343, 0, 4093, 0, 1715, 0, 0, 0, - 1102, 0, 1293, 0, 3511, 4480, 1580, 0, 0, 0, 3696, 2606, 4260, 598, 0, - 0, 1481, 1834, 1386, 0, 0, 3233, 0, 0, 0, 148, 736, 0, 0, 0, 1277, 6, - 0, 0, 256, 0, 0, 0, 0, 0, 2751, 0, 3301, 0, 928, 0, 2235, 0, 3526, 0, - 0, 0, 0, 0, 0, 0, 2064, 0, 680, 1145, 0, 3846, 0, 2921, 3958, 0, 0, - 110, 669, 0, 0, 0, 0, 0, 0, 0, 2900, 1971, 0, 0, 1634, 0, 0, 0, 2455, - 0, 0, 0, 1421, 0, 0, 0, 0, 0, 2806, 0, 1373, 0, 1381, 0, 577, 1230, 0, - 1530, 0, 0, 0, 0, 0, 0, 1475, 0, 0, 0, 958, 0, 0, 1191, 705, 0, 0, 0, - 4119, 0, 1374, 0, 0, 0, 0, 0, 0, 0, 2184, 0, 1448, 453, 0, 0, 0, 0, - 1679, 0, 0, 319, 0, 0, 919, 3694, 0, 1245, 3819, 3927, 0, 172, 4124, - 915, 2260, 1603, 2195, 0, 3959, 0, 961, 0, 0, 3181, 0, 124, 4189, 0, - 1643, 4214, 0, 0, 0, 0, 705, 0, 1686, 0, 0, 0, 0, 2321, 0, 0, 0, 0, 0, - 0, 948, 964, 0, 0, 0, 0, 3849, 0, 1037, 130, 0, 0, 1662, 798, 1797, - 2980, 3661, 2866, 0, 1533, 919, 0, 3384, 0, 4285, 1888, 541, 2202, 0, - 0, 1730, 88, 975, 0, 2318, 0, 3481, 863, 862, 0, 3029, 2012, 0, 4486, - 3041, 0, 0, 1749, 0, 552, 1638, 735, 849, 2412, 0, 15, 4381, 1927, 0, - 0, 0, 1743, 407, 0, 588, 1961, 3990, 0, 3326, 986, 0, 0, 0, 0, 0, 3103, - 0, 249, 2485, 0, 114, 0, 0, 0, 0, 0, 0, 1605, 1579, 0, 224, 0, 0, 0, 0, - 0, 0, 4363, 0, 3210, 2143, 2438, 933, 0, 811, 731, 3322, 628, 0, 4116, - 0, 1439, 0, 3792, 1352, 4500, 1048, 1852, 1063, 1949, 4175, 2115, 0, 0, - 0, 0, 0, 180, 1011, 4544, 0, 2781, 2908, 2563, 0, 3858, 0, 0, 844, - 3784, 3094, 0, 2768, 0, 0, 0, 4527, 0, 4104, 0, 0, 0, 0, 1248, 0, 0, - 2496, 3924, 0, 211, 0, 0, 0, 1218, 0, 0, 1595, 345, 0, 0, 1444, 1935, - 0, 3115, 0, 0, 3649, 0, 1040, 2017, 0, 0, 0, 1522, 0, 0, 3024, 3612, 0, - 0, 0, 0, 1031, 3795, 580, 0, 3273, 1797, 2115, 4601, 0, 0, 0, 0, 2873, - 1332, 3168, 2952, 374, 1139, 3970, 186, 0, 3444, 0, 3238, 0, 4557, 888, - 0, 4071, 0, 92, 3329, 0, 0, 160, 0, 0, 1450, 1422, 1144, 1696, 0, 0, 0, - 0, 138, 0, 0, 0, 0, 3634, 0, 0, 0, 0, 4182, 626, 0, 0, 1974, 1305, - 2524, 4059, 535, 289, 0, 0, 0, 0, 1546, 0, 4220, 0, 0, 0, 0, 624, 0, 0, - 2144, 584, 3312, 535, 0, 970, 0, 0, 1139, 0, 0, 3207, 532, 3446, 2410, - 1605, 0, 1655, 0, 3869, 0, 1079, 0, 332, 1765, 0, 989, 0, 3144, 818, - 1602, 0, 0, 2761, 0, 0, 232, 1095, 0, 2200, 1626, 0, 2165, 0, 0, 1681, - 0, 0, 0, 0, 0, 1081, 0, 0, 0, 1787, 0, 1245, 3068, 3485, 1914, 0, 0, - 4476, 0, 1039, 0, 637, 0, 0, 338, 1904, 1747, 0, 1227, 0, 135, 0, 1638, - 3771, 730, 1092, 1239, 0, 4036, 2489, 0, 0, 1749, 2907, 1886, 3113, - 2267, 0, 0, 0, 0, 0, 0, 1930, 0, 2239, 0, 0, 420, 521, 0, 0, 4356, - 1962, 1718, 278, 0, 4248, 0, 189, 0, 1734, 0, 0, 3171, 3564, 0, 0, 0, - 1452, 0, 4249, 4262, 3259, 0, 0, 28, 0, 1559, 0, 2154, 2472, 218, 1080, - 2010, 0, 964, 0, 0, 0, 2607, 1589, 2117, 1411, 895, 2067, 0, 0, 0, 0, - 0, 2282, 53, 3580, 0, 2679, 622, 365, 206, 3624, 642, 714, 0, 0, 3693, - 2249, 0, 0, 0, 1433, 370, 4312, 4208, 2245, 829, 1782, 0, 2416, 0, - 2926, 0, 4560, 1314, 2468, 1580, 2366, 0, 683, 2894, 0, 4547, 0, 624, - 0, 0, 1804, 0, 0, 1737, 0, 0, 0, 0, 0, 0, 2763, 1437, 0, 0, 1096, 0, - 4274, 2207, 0, 0, 2302, 0, 2379, 0, 66, 0, 869, 2147, 0, 1965, 2232, 0, - 0, 0, 0, 0, 0, 3051, 0, 1905, 0, 2045, 4358, 0, 2225, 0, 244, 2986, - 1126, 0, 718, 0, 1120, 0, 591, 0, 469, 3500, 4232, 2086, 0, 3726, 0, - 2973, 4223, 1741, 3823, 2909, 153, 184, 0, 2377, 3951, 0, 0, 766, 0, 0, - 0, 0, 0, 0, 253, 0, 2279, 2023, 0, 2965, 2182, 915, 3449, 1398, 175, 0, - 0, 290, 3096, 3091, 410, 0, 0, 0, 0, 911, 4475, 0, 4503, 1588, 1680, - 4136, 0, 255, 259, 0, 2413, 2771, 4384, 0, 0, 1381, 2078, 0, 4240, 578, - 0, 0, 1319, 2951, 2832, 818, 0, 0, 0, 2728, 0, 0, 0, 751, 43, 3955, - 2081, 1876, 871, 937, 1026, 1328, 4459, 0, 0, 1860, 4474, 2909, 2379, - 0, 1129, 0, 0, 1625, 0, 0, 0, 4514, 1404, 141, 3582, 1788, 2987, 3774, - 1343, 0, 3481, 0, 436, 0, 0, 0, 1630, 0, 0, 0, 0, 2182, 0, 0, 2755, - 463, 707, 1759, 1837, 0, 0, 2235, 926, 0, 1328, 2140, 0, 1136, 0, 0, 0, - 0, 2071, 101, 0, 0, 628, 0, 4409, 0, 1804, 3327, 3812, 0, 0, 0, 0, - 2114, 978, 0, 2612, 2144, 139, 0, 1543, 381, 727, 4498, 4344, 0, 0, - 1267, 3264, 1752, 391, 0, 0, 2204, 198, 1713, 0, 3407, 0, 4234, 1749, - 0, 4374, 1296, 3933, 790, 0, 0, 1214, 3468, 269, 2400, 0, 2157, 0, - 4310, 0, 0, 62, 1455, 1359, 1391, 0, 0, 0, 0, 0, 0, 0, 2153, 2300, 0, - 0, 1233, 130, 2209, 0, 5, 0, 0, 4421, 0, 1269, 2201, 2683, 2940, 3783, - 287, 644, 0, 3997, 1570, 4407, 4423, 0, 2572, 0, 4096, 0, 2301, 0, 0, - 3111, 870, 248, 2271, 0, 4111, 0, 0, 2094, 0, 0, 0, 0, 3622, 2313, - 1585, 0, 0, 903, 0, 774, 104, 0, 0, 0, 0, 0, 983, 0, 1073, 2464, 366, - 0, 0, 788, 1758, 563, 0, 741, 1794, 1707, 0, 2141, 0, 2633, 0, 1880, - 617, 284, 0, 635, 0, 226, 422, 0, 1232, 0, 0, 440, 654, 3301, 0, 267, - 0, 431, 39, 429, 0, 0, 0, 2768, 0, 0, 0, 4602, 2753, 4367, 2059, 0, - 3363, 2010, 805, 0, 0, 633, 0, 0, 4557, 462, 4236, 0, 735, 3597, 0, - 287, 0, 0, 4161, 0, 0, 4380, 1109, 1987, 0, 2277, 0, 2211, 0, 0, 3264, - 491, 1566, 485, 0, 0, 0, 0, 0, 0, 0, 1142, 907, 0, 0, 2010, 1379, 0, - 178, 3780, 0, 0, 0, 2127, 4601, 1494, 1275, 0, 0, 0, 0, 2632, 1392, - 4228, 1163, 0, 0, 0, 745, 0, 0, 1223, 0, 0, 0, 519, 1523, 515, 0, 0, - 3871, 0, 4002, 0, 3796, 0, 0, 2534, 0, 762, 0, 860, 0, 0, 1003, 1349, - 0, 0, 0, 0, 306, 0, 0, 0, 1760, 0, 1007, 495, 0, 1532, 185, 2669, 3181, - 0, 0, 3971, 0, 0, 27, 1049, 472, 3513, 2454, 1933, 1716, 0, 3364, 0, - 2597, 0, 234, 696, 1418, 0, 2100, 0, 0, 0, 4001, 2473, 0, 1781, 0, 0, - 4294, 0, 0, 293, 1345, 0, 0, 1840, 0, 855, 0, 517, 3163, 0, 0, 3812, - 865, 4600, 0, 1954, 0, 1267, 2672, 0, 2482, 0, 3318, 0, 2406, 1631, 0, - 0, 2261, 90, 605, 263, 3027, 175, 0, 434, 279, 497, 0, 0, 830, 0, 1097, - 3324, 2317, 0, 0, 0, 0, 535, 930, 1006, 3894, 0, 0, 233, 2599, 0, 1984, - 878, 132, 0, 777, 1007, 0, 1915, 0, 2367, 0, 3809, 1795, 2548, 3121, - 3382, 0, 3246, 3604, 1682, 0, 2422, 3699, 4064, 0, 2980, 0, 1937, 4228, - 1143, 0, 0, 3321, 2025, 0, 4564, 0, 2357, 466, 0, 3854, 1745, 2416, 0, - 3845, 296, 0, 0, 3195, 0, 3168, 0, 0, 0, 0, 499, 0, 1658, 0, 3119, 0, - 1731, 82, 228, 3877, 2026, 1595, 0, 0, 3541, 1895, 0, 0, 767, 0, 4595, - 0, 1536, 818, 1507, 0, 3676, 235, 0, 1801, 0, 4148, 1692, 3004, 3985, - 581, 0, 955, 0, 0, 0, 383, 0, 0, 941, 0, 529, 0, 2423, 1332, 679, 2017, - 3749, 2935, 0, 4482, 2651, 0, 0, 616, 0, 4335, 0, 4010, 0, 0, 0, 837, - 0, 0, 2108, 0, 0, 4189, 3018, 1915, 0, 0, 0, 0, 0, 0, 67, 3850, 0, 0, - 637, 2294, 249, 0, 1705, 3319, 3343, 2025, 1800, 1513, 3723, 0, 0, 0, - 4239, 0, 2828, 1365, 0, 0, 2007, 628, 2553, 0, 510, 4090, 2551, 2836, - 217, 0, 0, 0, 193, 0, 0, 0, 531, 0, 0, 301, 0, 439, 66, 60, 2424, 0, 0, - 4269, 0, 1094, 654, 0, 4218, 4608, 630, 3828, 847, 237, 0, 0, 0, 4415, - 30, 1007, 2453, 2039, 615, 4456, 0, 1432, 0, 179, 4140, 0, 988, 3955, - 2262, 0, 0, 873, 3859, 0, 545, 0, 2543, 1091, 4553, 6, 841, 0, 0, 143, - 860, 0, 0, 1336, 0, 0, 1627, 892, 4580, 0, 3267, 0, 919, 2152, 377, - 2556, 0, 4405, 129, 1535, 900, 0, 1426, 0, 0, 1134, 0, 738, 0, 3200, - 436, 0, 1241, 0, 2425, 0, 3597, 691, 1728, 1105, 0, 0, 0, 937, 3577, - 255, 364, 3974, 183, 0, 0, 0, 0, 71, 860, 2200, 0, 0, 0, 3817, 3856, - 765, 1237, 3820, 1840, 1592, 547, 0, 0, 542, 0, 1386, 0, 3194, 0, 0, - 918, 715, 2575, 0, 256, 3402, 2305, 1117, 0, 240, 0, 0, 86, 0, 0, 934, - 0, 3746, 0, 3776, 0, 1745, 2258, 3606, 2716, 0, 0, 3380, 0, 36, 170, - 3354, 2447, 2571, 1976, 0, 553, 0, 1654, 2595, 2426, 0, 0, 1435, 4502, - 2174, 526, 2118, 0, 3004, 0, 0, 3553, 1499, 0, 2360, 3802, 3932, 2544, - 0, 2341, 0, 0, 406, 0, 0, 0, 0, 3820, 303, 0, 0, 0, 0, 1006, 1322, - 1603, 894, 0, 0, 0, 0, 2002, 0, 0, 868, 2332, 0, 3993, 1107, 213, 0, - 534, 1744, 617, 0, 378, 1966, 2463, 0, 0, 3333, 0, 2483, 1505, 1008, 0, - 914, 0, 1005, 0, 0, 3978, 0, 1062, 2183, 3810, 0, 633, 0, 2866, 2950, - 530, 0, 3081, 0, 2158, 290, 4013, 60, 974, 2463, 4185, 613, 1066, 2099, - 3681, 2893, 0, 462, 0, 0, 0, 0, 71, 3446, 2689, 0, 1458, 0, 1159, 0, - 1326, 2626, 0, 0, 0, 1011, 0, 0, 625, 523, 188, 3452, 1826, 2554, 2243, - 0, 542, 2298, 0, 2176, 0, 0, 0, 4112, 0, 3376, 1686, 0, 3258, 356, 0, - 0, 1015, 2858, 4075, 218, 207, 4411, 227, 1112, 4155, 0, 2996, 2209, - 4167, 1809, 532, 1871, 581, 3529, 164, 0, 54, 0, 0, 0, 204, 0, 981, - 205, 698, 0, 1198, 876, 0, 0, 281, 1156, 0, 0, 1948, 896, 1216, 2964, - 4532, 1032, 0, 4045, 1614, 122, 4404, 0, 559, 0, 3889, 4511, 2619, - 4200, 832, 0, 0, 2799, 546, 623, 1853, 0, 0, 274, 0, 905, 0, 480, 1532, - 1380, 4215, 0, 0, 57, 585, 2423, 3731, 0, 311, 1146, 1236, 2745, 0, - 2676, 1777, 0, 0, 4077, 0, 0, 642, 1066, 921, 0, 833, 0, 0, 71, 2658, - 0, 223, 0, 4017, 1086, 1800, 0, 0, 1453, 0, 0, 4541, 0, 0, 3175, 0, - 870, 0, 0, 378, 0, 0, 3643, 0, 0, 205, 3816, 3158, 0, 465, 0, 239, 0, - 0, 0, 309, 665, 0, 0, 1397, 655, 917, 581, 10, 2291, 0, 0, 0, 4392, - 2465, 223, 4182, 947, 0, 1530, 2691, 0, 2405, 0, 125, 0, 479, 0, 1188, - 2858, 0, 814, 2712, 2447, 2373, 2391, 0, 0, 1653, 0, 2295, 0, 2736, - 3257, 287, 0, 554, 0, 882, 2409, 1854, 0, 1891, 3313, 0, 4574, 0, 196, - 0, 2396, 4395, 0, 930, 2906, 804, 0, 4336, 0, 0, 0, 0, 0, 1249, 0, - 3064, 0, 3055, 0, 0, 3399, 2788, 0, 745, 858, 3845, 0, 29, 4498, 1254, - 1308, 250, 627, 3163, 558, 1144, 0, 2723, 62, 0, 1372, 0, 0, 0, 728, - 3471, 3070, 4491, 1648, 4362, 0, 155, 910, 0, 2497, 0, 0, 20, 0, 397, - 0, 747, 577, 437, 0, 4222, 0, 0, 0, 0, 435, 0, 0, 0, 0, 2355, 0, 3339, - 2267, 4401, 4448, 252, 0, 4523, 288, 0, 818, 0, 315, 0, 2233, 0, 1671, - 919, 0, 2042, 1254, 2316, 711, 0, 0, 1327, 610, 0, 0, 1215, 0, 1043, 0, - 558, 0, 154, 2364, 1428, 1560, 1622, 3498, 1541, 3533, 694, 3476, 0, 0, - 0, 306, 0, 0, 0, 4503, 0, 0, 0, 4496, 0, 142, 0, 900, 1222, 832, 346, - 0, 1700, 1914, 0, 0, 0, 1049, 3362, 0, 0, 0, 883, 0, 87, 0, 0, 0, 0, - 1249, 1116, 3474, 0, 1015, 0, 2177, 73, 4422, 0, 0, 0, 0, 2259, 2647, - 0, 0, 0, 0, 0, 4532, 0, 0, 2310, 0, 0, 0, 2162, 0, 709, 1778, 671, - 1488, 1389, 92, 1047, 638, 73, 1577, 0, 0, 1053, 1529, 0, 1138, 0, - 1258, 1938, 649, 0, 0, 404, 3705, 873, 0, 0, 0, 0, 1433, 1119, 0, 3556, - 4111, 2528, 4224, 4236, 3549, 1012, 2155, 2065, 0, 0, 0, 0, 783, 831, - 0, 3826, 3812, 3841, 0, 2214, 0, 1583, 0, 0, 0, 3528, 0, 2560, 1189, 0, - 0, 1637, 0, 3483, 0, 0, 0, 0, 0, 1151, 197, 1234, 0, 0, 764, 318, 239, - 2111, 0, 0, 205, 3414, 0, 824, 1355, 0, 2436, 2872, 2604, 4417, 640, - 2440, 759, 0, 2458, 0, 0, 1550, 1282, 2682, 0, 1971, 0, 0, 1330, 1818, - 2694, 2530, 1567, 1004, 114, 0, 1109, 2852, 2596, 1229, 1396, 2197, - 4051, 0, 0, 41, 53, 1542, 0, 0, 1050, 2473, 0, 2570, 593, 0, 1806, - 2811, 0, 629, 40, 601, 0, 2874, 0, 3440, 3877, 803, 3827, 3381, 202, 0, - 2568, 243, 4315, 0, 2164, 0, 3015, 4160, 0, 0, 2462, 297, 1563, 0, - 1877, 0, 0, 480, 0, 3791, 2430, 0, 0, 0, 0, 0, 504, 872, 2585, 116, 0, - 1023, 0, 782, 0, 0, 0, 4353, 2481, 331, 0, 1668, 0, 0, 0, 0, 3679, 0, - 0, 0, 3174, 0, 1096, 0, 0, 2792, 0, 0, 704, 2341, 1221, 513, 202, 1736, - 0, 0, 2268, 149, 2070, 1568, 95, 0, 136, 2261, 0, 0, 2622, 4424, 0, - 1505, 2288, 1672, 2462, 590, 4480, 4222, 0, 0, 2020, 0, 2227, 2602, - 3669, 2740, 0, 2700, 0, 0, 0, 0, 0, 417, 0, 0, 70, 3309, 2814, 2347, - 921, 0, 1029, 4373, 0, 0, 0, 4327, 0, 347, 48, 884, 0, 0, 3796, 470, - 1033, 1386, 1632, 37, 926, 761, 372, 1928, 127, 787, 4465, 0, 0, 923, - 826, 1147, 0, 0, 96, 883, 2670, 1012, 0, 0, 0, 1237, 2499, 976, 705, - 4051, 1332, 0, 0, 413, 0, 3412, 3824, 4250, 0, 1380, 1295, 614, 1378, - 0, 0, 0, 0, 316, 0, 0, 0, 0, 0, 111, 1586, 0, 0, 0, 1715, 0, 494, 0, 0, - 0, 2425, 3402, 0, 3759, 0, 773, 618, 4035, 2818, 321, 0, 2050, 3091, - 1875, 0, 12, 4534, 2346, 0, 0, 2224, 2494, 573, 0, 2467, 4379, 97, 547, - 0, 0, 1126, 634, 0, 0, 0, 0, 4510, 2430, 0, 0, 0, 1849, 162, 2500, 0, - 1932, 847, 0, 4505, 0, 1749, 1687, 1183, 3352, 0, 0, 3263, 0, 2074, 68, - 0, 9, 1692, 1165, 0, 0, 2415, 3487, 2402, 1155, 2471, 2179, 0, 891, 0, - 1732, 184, 0, 3584, 0, 0, 0, 1790, 0, 2502, 0, 2339, 0, 2156, 583, 0, - 0, 237, 0, 3055, 621, 2873, 17, 3302, 1205, 3182, 1636, 264, 1510, - 3706, 0, 0, 734, 0, 0, 4141, 2390, 4440, 2286, 2561, 3228, 0, 1719, 0, - 2225, 4182, 2101, 1214, 0, 1628, 0, 0, 2804, 4544, 3734, 646, 501, - 1921, 1804, 0, 4148, 2343, 206, 2206, 0, 2000, 550, 2543, 260, 3883, - 653, 972, 4075, 2036, 866, 0, 1030, 0, 0, 0, 1336, 4116, 0, 1831, 1332, - 0, 2216, 0, 0, 939, 1267, 3400, 4398, 3801, 2234, 1339, 0, 0, 313, - 3737, 0, 244, 1165, 0, 4271, 890, 463, 0, 0, 646, 0, 0, 133, 0, 162, 0, - 1791, 1633, 1480, 0, 0, 0, 1743, 0, 1967, 0, 1714, 0, 2051, 1196, 3304, - 0, 0, 1287, 3761, 3347, 753, 3749, 0, 2736, 1013, 3281, 177, 0, 4370, - 0, 3110, 1565, 1569, 1086, 1442, 0, 3796, 2406, 285, 0, 0, 902, 0, 0, - 1488, 0, 0, 0, 4533, 3261, 3929, 3390, 1440, 369, 2284, 4186, 1132, - 1257, 0, 0, 1514, 0, 1720, 0, 4227, 1248, 2779, 1534, 2056, 1772, 321, - 0, 2719, 0, 0, 731, 0, 0, 563, 176, 0, 450, 0, 0, 0, 0, 4201, 0, 1964, - 2538, 0, 0, 901, 2411, 0, 2097, 0, 0, 0, 0, 3678, 0, 1259, 1287, 4138, - 0, 3658, 1067, 766, 2791, 706, 639, 0, 160, 1653, 1961, 0, 1497, 0, - 1714, 0, 4199, 1424, 505, 4117, 4235, 2852, 842, 0, 451, 0, 838, 1006, - 430, 4610, 1644, 0, 788, 1707, 246, 0, 921, 0, 0, 0, 250, 926, 4486, - 329, 1382, 3992, 1054, 2256, 614, 0, 0, 1743, 3996, 325, 0, 0, 0, 0, - 1654, 4577, 723, 0, 0, 0, 1243, 1267, 0, 0, 0, 0, 3819, 2042, 486, 0, - 0, 1446, 687, 3841, 1664, 2385, 4582, 0, 0, 0, 0, 1339, 830, 2509, 0, - 0, 0, 0, 3532, 335, 3905, 1706, 0, 874, 0, 0, 1106, 3539, 1199, 0, 0, - 2688, 1065, 2817, 0, 44, 580, 1099, 893, 2617, 0, 2571, 0, 0, 203, 228, - 961, 1787, 0, 2056, 0, 0, 571, 2118, 3892, 0, 2640, 620, 0, 1166, 2975, - 1212, 2966, 0, 176, 1805, 314, 4300, 1034, 0, 1316, 731, 361, 596, - 1083, 4433, 1827, 3669, 1629, 686, 0, 2380, 0, 988, 889, 1433, 1278, - 1363, 0, 0, 2213, 209, 2990, 228, 0, 0, 1179, 19, 534, 1062, 4294, 463, - 3295, 0, 4531, 0, 0, 1578, 0, 2807, 0, 0, 0, 0, 0, 0, 448, 0, 1595, 0, - 2922, 1872, 1243, 1189, 0, 2586, 3121, 0, 0, 1263, 0, 3288, 0, 0, 0, - 2882, 2272, 4544, 589, 103, 1466, 75, 0, 0, 349, 160, 0, 4510, 0, 2485, - 0, 0, 2812, 571, 0, 0, 2205, 386, 3903, 362, 0, 2387, 3385, 2353, 1303, - 3442, 0, 1021, 3696, 0, 0, 336, 3101, 4507, 0, 0, 1335, 1048, 0, 2641, - 3275, 3293, 869, 0, 1030, 0, 1383, 0, 0, 0, 4110, 0, 0, 1584, 0, 0, - 2873, 0, 2601, 0, 0, 344, 1734, 2334, 1290, 1370, 0, 83, 2187, 0, 0, - 1141, 0, 2065, 3629, 0, 0, 0, 0, 340, 0, 0, 4566, 4201, 643, 3620, - 1491, 0, 1180, 1962, 0, 2606, 351, 605, 0, 551, 0, 1520, 2401, 1995, 0, - 1323, 2138, 4315, 0, 2770, 0, 0, 0, 3310, 441, 58, 1520, 3033, 4473, 0, - 3066, 0, 1759, 831, 555, 0, 2672, 0, 0, 875, 1343, 4368, 2535, 0, 0, - 591, 0, 0, 0, 0, 2039, 376, 0, 1248, 0, 1605, 0, 0, 1486, 0, 944, 3619, - 0, 836, 2314, 0, 4053, 2147, 1130, 0, 1364, 356, 4200, 3896, 926, 341, - 3918, 3942, 0, 1046, 1208, 0, 0, 361, 2021, 4485, 0, 4488, 0, 3303, 0, - 1439, 1389, 3130, 0, 4346, 3865, 813, 1449, 3573, 2263, 151, 153, 1598, - 2397, 0, 1248, 251, 289, 2109, 1285, 3958, 2980, 1891, 0, 1516, 0, - 2274, 122, 358, 737, 0, 1444, 1369, 0, 985, 0, 2199, 24, 0, 597, 390, - 1040, 2072, 0, 1131, 2091, 2507, 1217, 3678, 3732, 1021, 1228, 0, 0, - 2868, 3671, 2657, 2081, 364, 4066, 1106, 0, 0, 1716, 828, 1817, 0, - 3993, 0, 0, 0, 4000, 2831, 2951, 387, 594, 2834, 0, 0, 2237, 2688, - 3568, 2140, 0, 0, 1457, 1913, 1265, 0, 2056, 0, 0, 1367, 561, 0, 0, 0, - 2204, 684, 343, 0, 1320, 1005, 1464, 3689, 1270, 366, 565, 0, 2318, 0, - 3246, 2424, 1503, 1410, 945, 3096, 3243, 1874, 731, 0, 4409, 1732, 0, - 1143, 122, 0, 2039, 1920, 2508, 2469, 0, 827, 3265, 4577, 1938, 1924, - 1366, 3392, 2133, 1411, 0, 0, 0, 1778, 4385, 0, 1085, 4018, 0, 0, 851, - 389, 3421, 771, 2504, 0, 2227, 3506, 0, 71, 4089, 1997, 0, 1355, 34, 0, - 0, 1774, 0, 0, 0, 0, 1107, 2539, 0, 1664, 0, 3035, 0, 3117, 2014, 245, - 0, 81, 3117, 4399, 3652, 2086, 0, 0, 656, 0, 1010, 3285, 1335, 0, 1501, - 2195, 2213, 0, 1333, 558, 1535, 3015, 3963, 703, 0, 456, 1735, 412, - 745, 1064, 8, 807, 1493, 1564, 1390, 2586, 0, 739, 3194, 135, 3929, 0, - 787, 430, 2148, 2309, 0, 1080, 4224, 3913, 4309, 466, 0, 0, 3302, 3408, - 397, 4620, 0, 411, 0, 256, 2185, 0, 1066, 1301, 2287, 0, 4292, 0, 0, - 102, 3485, 2575, 1201, 3669, 4061, 4340, 2888, 1305, 0, 0, 453, 3104, - 3647, 0, 1348, 520, 2521, 2113, 0, 459, 2900, 4234, 4050, 2278, 2529, - 0, 6, 0, 1711, 1362, 1204, 747, 4578, 3718, 0, 1873, 2829, 1542, 983, - 1638, 1507, 0, 414, 1161, 1181, 3012, 222, 0, 2271, 3941, 1068, 398, 0, - 0, 0, 0, 0, 0, 0, 0, 67, 1189, 0, 2519, 0, 846, 0, 0, 162, 1068, 870, - 3380, 0, 4570, 4374, 1970, 0, 3059, 0, 1821, 0, 418, 0, 1909, 0, 0, 0, - 0, 1286, 1842, 961, 407, 2740, 2832, 1931, 993, 0, 798, 2842, 0, 4248, - 2552, 3761, 1170, 2281, 0, 69, 34, 2297, 179, 3307, 0, 3146, 0, 1554, - 556, 0, 229, 1474, 1356, 2240, 0, 1233, 3397, 2875, 1137, 1250, 4343, - 0, 0, 213, 674, 2269, 0, 4053, 0, 1353, 1871, 616, 1518, 437, 104, - 3276, 1895, 4301, 2275, 1521, 2497, 1775, 0, 3829, 3129, 658, 4593, - 789, 4295, 583, 708, 2539, 1938, 0, 2610, 3108, 0, 1620, 1933, 493, - 718, 3941, 0, 3748, 0, 0, 2434, 1280, 0, 735, 2293, 2956, 2798, 0, 0, - 0, 480, 4154, 3738, 2705, 0, 0, 1301, 3969, 0, 0, 1974, 4057, 2092, - 910, 1708, 2732, 510, 0, 1819, 0, 3562, 2338, 3929, 212, 3852, 0, 3318, - 4378, 0, 148, 507, 1822, 1416, 0, 487, 3233, 0, 0, 2242, 607, 97, 1496, - 425, 38, 0, 0, 48, 1612, 3603, 0, 2139, 1016, 2310, 0, 1917, 3513, 0, - 0, 4333, 2574, 0, 2170, 1026, 0, 2613, 4262, 0, 1107, 0, 0, 1691, 1385, - 2971, 2157, 1153, 1309, 423, 4317, 0, 994, 3276, 2401, 4063, 536, 2403, - 1251, 1357, 3771, 2415, 2812, 1896, 2280, 0, 0, 512, 692, 3638, 0, - 2231, 123, 0, 2017, 4363, 496, 1503, 0, 3607, 0, 417, 3197, 1509, 1918, - 0, 2280, 3730, 3992, 0, 4361, 0, 402, 0, 0, 2690, 0, 2116, 152, 0, - 1403, 2620, 288, 0, 859, 1894, 1246, 2014, 1944, 2145, 2766, 1182, 62, - 0, 0, 1307, 4508, 0, 472, 958, 0, 0, 1795, 2412, 2951, 0, 1781, 3150, - 1845, 1163, 0, 0, 1246, 3141, 1225, 434, 1052, 460, 3206, 0, 4572, 0, - 636, 549, 1898, 0, 0, 1185, 0, 2421, 266, 746, 0, 0, 0, 3667, 2161, - 2765, 2831, 0, 1076, 0, 487, 0, 2143, 1303, 0, 4256, 4317, 0, 0, 88, - 2270, 0, 4528, 288, 0, 393, 0, 716, 0, 2165, 200, 0, 0, 0, 2511, 0, - 1302, 528, 0, 1541, 1204, 3221, 511, 1160, 0, 1609, 158, 154, 2878, - 442, 3063, 2189, 271, 0, 0, 0, 0, 98, 3841, 843, 2459, 3907 + 0, 0, 0, 0, 3675, 0, 1841, 0, 0, 3075, 0, 0, 1109, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2462, 1977, 550, 0, 0, 0, 0, + 0, 0, 0, 1456, 0, 0, 0, 0, 0, 0, 1111, 0, 0, 0, 3965, 0, 1830, 0, 0, 0, + 0, 1482, 0, 0, 0, 0, 2706, 1113, 0, 0, 0, 0, 0, 2924, 0, 0, 1109, 0, 0, + 0, 2702, 2859, 0, 0, 3730, 0, 595, 0, 0, 115, 0, 4324, 3261, 0, 0, + 2562, 0, 0, 0, 2130, 780, 4058, 0, 0, 0, 2070, 0, 0, 0, 0, 1345, 0, + 2456, 0, 0, 2626, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 1340, 0, 0, 2745, + 2132, 0, 0, 0, 1106, 1069, 0, 0, 0, 0, 0, 0, 76, 0, 0, 2797, 2461, 0, + 0, 0, 0, 0, 0, 290, 0, 0, 0, 0, 664, 4289, 0, 0, 3276, 0, 0, 0, 0, 0, + 4561, 0, 0, 3840, 0, 0, 0, 3544, 0, 0, 0, 0, 632, 1505, 0, 4215, 0, + 2163, 1020, 0, 0, 0, 3713, 2267, 0, 0, 2381, 0, 2204, 0, 0, 0, 0, 1415, + 3533, 3110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3370, 0, 0, 0, + 120, 0, 173, 0, 1228, 0, 0, 0, 0, 1675, 0, 0, 3053, 1581, 0, 0, 0, 854, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2685, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2512, + 1244, 1598, 0, 0, 0, 258, 0, 0, 0, 4167, 785, 1855, 0, 1980, 3051, + 3339, 0, 0, 2378, 0, 3861, 0, 2357, 0, 0, 1380, 4329, 0, 3181, 0, 0, 0, + 0, 0, 0, 0, 0, 1932, 3799, 0, 51, 0, 0, 0, 4532, 0, 853, 0, 0, 0, 0, 0, + 0, 3908, 0, 0, 4030, 2560, 1284, 0, 0, 0, 0, 0, 0, 0, 2539, 3778, 0, + 3552, 4279, 0, 0, 0, 0, 4230, 629, 3256, 0, 1122, 0, 0, 0, 0, 460, + 3313, 0, 3118, 0, 4503, 0, 0, 0, 587, 0, 0, 0, 111, 0, 0, 0, 0, 0, 0, + 0, 3046, 981, 0, 0, 1155, 775, 3321, 0, 0, 1184, 0, 0, 1852, 0, 3084, + 4322, 2092, 0, 0, 0, 2699, 2530, 0, 0, 0, 1533, 0, 0, 0, 2379, 1234, 0, + 0, 0, 3327, 1111, 0, 0, 3275, 0, 0, 1159, 0, 0, 0, 0, 389, 1653, 528, + 1079, 0, 801, 2832, 3792, 0, 3362, 0, 0, 0, 0, 0, 0, 0, 3219, 4359, 0, + 58, 0, 989, 0, 0, 2562, 0, 1935, 2179, 0, 2948, 127, 0, 0, 1836, 3877, + 0, 0, 492, 0, 0, 4327, 0, 0, 0, 4408, 0, 0, 0, 2802, 0, 740, 0, 635, 0, + 0, 0, 0, 0, 0, 2576, 372, 0, 0, 0, 0, 2115, 0, 0, 0, 0, 0, 3971, 1436, + 2541, 2327, 0, 750, 0, 0, 0, 0, 3875, 1684, 1756, 889, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2191, 0, 0, 0, 0, 706, 402, 3245, 247, 1482, 156, 1342, + 3364, 0, 2127, 0, 0, 3232, 0, 0, 0, 0, 0, 0, 0, 3925, 0, 1972, 1541, 0, + 0, 0, 1813, 0, 2195, 0, 0, 0, 0, 0, 1203, 2947, 0, 413, 0, 0, 0, 3813, + 167, 3199, 0, 3528, 803, 2340, 4413, 4267, 4585, 2122, 1089, 0, 615, 0, + 2223, 0, 1829, 0, 869, 2828, 0, 339, 1520, 0, 3686, 0, 1698, 3325, 0, + 133, 0, 0, 0, 0, 1902, 0, 0, 0, 3724, 1193, 4078, 229, 0, 1621, 0, + 1719, 0, 2970, 0, 0, 793, 3412, 508, 0, 518, 0, 0, 2300, 968, 424, 689, + 0, 726, 1788, 418, 480, 0, 990, 0, 3645, 1358, 0, 1217, 3045, 0, 3028, + 3803, 0, 4150, 189, 3729, 0, 496, 281, 0, 3448, 0, 1662, 0, 0, 614, 0, + 0, 881, 0, 374, 0, 1143, 0, 681, 0, 0, 1251, 0, 342, 0, 169, 2070, 0, + 0, 478, 508, 0, 0, 1286, 4198, 0, 0, 2058, 0, 1885, 1332, 0, 0, 0, + 2097, 0, 0, 0, 2042, 420, 2417, 0, 0, 0, 790, 2709, 4042, 1243, 2287, + 0, 294, 342, 0, 0, 568, 0, 2208, 0, 0, 0, 0, 25, 120, 0, 0, 0, 846, 0, + 2565, 1662, 4121, 0, 4043, 0, 0, 1274, 554, 3445, 0, 426, 488, 3537, 0, + 0, 586, 4035, 3002, 0, 0, 0, 2915, 4143, 0, 0, 0, 0, 2244, 309, 0, + 4604, 0, 0, 0, 0, 0, 4321, 72, 0, 1416, 0, 0, 0, 0, 0, 2416, 0, 4213, + 0, 0, 0, 2589, 3732, 0, 0, 1035, 0, 0, 0, 717, 2343, 3060, 510, 2786, + 0, 1872, 944, 1867, 1322, 0, 0, 2392, 0, 0, 3744, 0, 428, 2998, 0, 0, + 0, 4608, 484, 4225, 0, 0, 0, 0, 4566, 0, 0, 2118, 0, 1118, 4203, 0, + 1657, 0, 0, 0, 371, 0, 1320, 0, 0, 0, 1945, 2232, 0, 2849, 0, 1696, + 1141, 3652, 0, 0, 365, 2287, 1354, 0, 0, 0, 490, 927, 0, 3116, 0, 2248, + 2026, 2852, 0, 3864, 0, 3034, 0, 1521, 0, 0, 590, 0, 0, 1573, 0, 0, + 3915, 0, 3537, 3689, 330, 449, 4129, 3864, 268, 3845, 0, 0, 0, 0, 0, + 3432, 0, 0, 953, 3014, 0, 0, 2563, 0, 0, 1018, 0, 4522, 2834, 442, 636, + 3127, 4493, 2761, 0, 3881, 0, 447, 432, 73, 663, 368, 387, 0, 1315, + 188, 0, 4531, 0, 393, 1230, 0, 0, 0, 0, 665, 0, 3180, 0, 3054, 1239, 0, + 357, 0, 720, 0, 136, 4191, 0, 321, 0, 3380, 0, 0, 0, 945, 0, 850, 3581, + 0, 1459, 1439, 0, 0, 2430, 0, 0, 3851, 0, 1333, 522, 2473, 0, 0, 0, + 3303, 785, 0, 0, 0, 2610, 2402, 2575, 0, 301, 252, 0, 0, 0, 0, 2941, + 453, 4187, 0, 1841, 2266, 40, 457, 0, 0, 1596, 0, 809, 277, 3505, 4403, + 0, 0, 0, 4266, 0, 0, 3504, 731, 2254, 0, 0, 0, 0, 0, 1553, 0, 3358, + 1621, 1804, 0, 0, 0, 0, 0, 496, 0, 0, 0, 4422, 1490, 4165, 0, 4039, + 455, 903, 1821, 1643, 518, 0, 1646, 0, 0, 0, 0, 353, 3175, 86, 428, + 663, 2437, 1625, 0, 2312, 2184, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 0, 0, + 3960, 0, 3117, 691, 0, 0, 1507, 2511, 0, 0, 538, 1017, 0, 2818, 0, + 1320, 0, 1764, 0, 1837, 197, 4386, 0, 0, 683, 1191, 0, 0, 0, 2567, + 2877, 0, 2656, 2759, 0, 397, 0, 0, 0, 2095, 2035, 4215, 770, 0, 0, 0, + 505, 0, 240, 0, 0, 785, 0, 0, 1232, 0, 801, 3884, 0, 0, 77, 2768, 0, + 1777, 3810, 0, 4244, 4430, 0, 111, 528, 999, 0, 1910, 3574, 0, 540, + 1575, 0, 0, 0, 0, 314, 424, 1548, 0, 3283, 2099, 413, 0, 334, 2383, + 154, 4375, 369, 3998, 0, 2610, 1565, 1975, 3825, 2159, 0, 461, 710, 0, + 0, 1946, 0, 0, 2018, 0, 0, 0, 1039, 0, 0, 305, 0, 0, 158, 1896, 0, 0, + 0, 1990, 0, 1121, 420, 1043, 0, 0, 3803, 115, 2599, 2066, 0, 0, 0, 0, + 0, 0, 0, 3799, 4594, 0, 3392, 2511, 0, 0, 0, 3476, 1371, 1527, 4549, + 647, 88, 1407, 0, 4305, 0, 2015, 0, 0, 0, 4410, 0, 0, 0, 0, 4484, 0, 0, + 1548, 0, 1845, 600, 0, 0, 4594, 0, 2101, 544, 0, 0, 3964, 0, 0, 1879, + 0, 0, 119, 0, 2934, 541, 0, 3768, 0, 3761, 0, 1993, 2153, 2796, 172, + 2706, 0, 0, 0, 284, 0, 2008, 0, 2333, 922, 0, 1766, 0, 3658, 1252, 754, + 0, 2635, 4472, 1273, 1899, 2349, 1731, 0, 713, 0, 0, 0, 1066, 0, 895, + 2412, 4592, 0, 0, 0, 20, 0, 0, 0, 2059, 4536, 3569, 470, 3145, 1073, + 3528, 0, 0, 2471, 1932, 927, 0, 108, 4235, 1992, 0, 1666, 182, 2181, 0, + 2401, 159, 0, 2988, 4579, 0, 657, 559, 0, 64, 1393, 651, 0, 1239, 4482, + 322, 0, 1850, 0, 1864, 0, 0, 0, 0, 3578, 4351, 0, 1430, 0, 1975, 0, 0, + 3962, 2981, 0, 1859, 1226, 0, 1250, 0, 0, 0, 1333, 1474, 0, 1306, 0, 0, + 347, 1718, 0, 0, 0, 4446, 3277, 0, 356, 0, 221, 962, 3382, 625, 1902, + 2171, 4544, 2745, 0, 1833, 1638, 3023, 1487, 513, 1470, 2301, 567, 0, + 2254, 1804, 0, 0, 130, 0, 1167, 0, 2471, 3762, 1013, 670, 0, 0, 0, 0, + 0, 0, 0, 1478, 4511, 579, 2563, 0, 3231, 0, 3371, 4028, 0, 2892, 3806, + 0, 0, 2407, 1561, 291, 2704, 0, 0, 3596, 2958, 4599, 0, 2508, 1003, + 1571, 0, 2798, 227, 0, 4464, 0, 0, 0, 1985, 0, 313, 2702, 0, 0, 2323, + 1704, 4293, 3435, 4491, 196, 14, 3708, 454, 0, 3726, 0, 4110, 1767, 0, + 2171, 0, 0, 0, 0, 584, 3, 0, 0, 1480, 2416, 0, 0, 3889, 1908, 954, 0, + 0, 0, 0, 2147, 1570, 1735, 0, 1314, 4270, 0, 4499, 3684, 0, 3936, 0, 0, + 3757, 0, 266, 0, 0, 0, 0, 2288, 4041, 674, 0, 4567, 0, 522, 153, 2387, + 2602, 0, 3335, 0, 753, 1981, 1108, 497, 0, 137, 0, 0, 0, 326, 0, 899, + 0, 15, 1999, 2496, 110, 0, 1727, 0, 1339, 0, 0, 0, 578, 0, 0, 0, 0, + 930, 874, 3506, 0, 2075, 0, 0, 915, 0, 983, 456, 4583, 0, 283, 953, 0, + 1872, 873, 0, 2338, 0, 0, 1954, 0, 2822, 4262, 0, 1694, 1352, 0, 0, 0, + 1067, 4323, 0, 2210, 2543, 0, 1525, 927, 0, 1071, 192, 1841, 0, 627, 0, + 4518, 1787, 0, 0, 958, 1300, 1097, 0, 131, 3792, 209, 0, 3273, 0, 0, 0, + 1420, 4174, 507, 1951, 563, 0, 351, 0, 1714, 0, 0, 0, 0, 503, 348, 0, + 625, 0, 3949, 0, 1401, 0, 0, 0, 872, 325, 0, 0, 334, 0, 4126, 2978, + 2344, 0, 2545, 1574, 0, 209, 2167, 23, 2141, 800, 0, 0, 0, 682, 1531, + 0, 90, 3124, 2362, 0, 0, 0, 2403, 0, 0, 0, 180, 0, 988, 1137, 323, 0, + 0, 0, 0, 0, 1864, 404, 1247, 3256, 3980, 0, 3395, 1094, 1458, 0, 0, 0, + 158, 0, 0, 0, 1634, 0, 596, 1449, 0, 0, 3403, 0, 0, 0, 4544, 1175, + 2128, 0, 2273, 0, 1566, 0, 2110, 3363, 0, 0, 0, 40, 0, 0, 45, 2245, + 2625, 2038, 2454, 95, 3048, 765, 0, 0, 380, 0, 0, 4270, 1002, 0, 1490, + 199, 0, 0, 0, 0, 0, 0, 72, 0, 3689, 1597, 0, 2706, 1233, 3722, 0, 4420, + 0, 0, 0, 1289, 0, 0, 819, 4473, 1730, 3907, 182, 0, 103, 853, 797, 0, + 2503, 1450, 4366, 0, 0, 0, 0, 1202, 3835, 2157, 3454, 1659, 3551, 0, 0, + 0, 1859, 2855, 4418, 3630, 0, 4180, 0, 0, 0, 1410, 0, 0, 2122, 0, 1544, + 3832, 0, 0, 438, 2457, 1669, 0, 0, 1589, 382, 4482, 0, 2453, 53, 3744, + 1840, 4421, 2427, 0, 3118, 0, 0, 2504, 0, 4167, 2323, 4153, 0, 0, 1478, + 0, 1962, 1295, 4315, 0, 0, 768, 1681, 2017, 0, 0, 444, 2214, 3813, 681, + 0, 0, 700, 0, 1621, 0, 0, 332, 0, 0, 0, 4455, 0, 0, 680, 0, 0, 517, + 1471, 1249, 0, 0, 0, 0, 0, 0, 2996, 4053, 2416, 0, 4009, 0, 0, 0, 0, + 362, 0, 0, 76, 0, 1913, 0, 0, 0, 3064, 0, 0, 0, 0, 2052, 963, 4059, 0, + 3956, 0, 3494, 1264, 1583, 3636, 2819, 0, 1690, 0, 0, 2851, 0, 101, 0, + 0, 1838, 0, 0, 1751, 2076, 0, 3062, 446, 1953, 2059, 716, 0, 4044, 0, + 1316, 1230, 0, 0, 766, 0, 1963, 3397, 3382, 249, 2339, 0, 0, 2479, 0, + 0, 2017, 2800, 293, 0, 3553, 4390, 0, 1088, 1215, 3818, 2193, 1880, + 3156, 0, 1014, 1355, 1569, 0, 0, 1234, 0, 4465, 0, 0, 1344, 4293, 0, 0, + 0, 3728, 0, 0, 0, 745, 83, 511, 2284, 0, 458, 0, 0, 0, 4262, 826, 0, 0, + 0, 0, 1453, 1756, 0, 283, 0, 2537, 4472, 90, 1414, 0, 1364, 38, 0, + 4007, 0, 942, 1330, 3625, 0, 0, 1291, 0, 3586, 0, 0, 1615, 0, 4591, + 852, 0, 0, 4126, 0, 2708, 1894, 2139, 0, 0, 781, 2667, 3227, 2517, 0, + 2057, 0, 0, 0, 0, 3021, 1240, 2062, 1086, 3096, 2825, 4356, 4387, 2016, + 422, 0, 2340, 0, 0, 0, 0, 0, 0, 4375, 429, 0, 994, 4290, 0, 0, 2550, + 3923, 1376, 0, 1915, 0, 0, 0, 0, 0, 0, 0, 2748, 220, 0, 0, 400, 0, 0, + 0, 1635, 0, 3031, 1250, 163, 4496, 206, 4473, 0, 0, 0, 2517, 720, 458, + 0, 0, 1153, 1934, 1207, 0, 1419, 1698, 0, 0, 0, 0, 0, 0, 239, 0, 788, + 2571, 3036, 0, 0, 0, 0, 2403, 0, 0, 0, 0, 573, 0, 1280, 0, 0, 374, 0, + 2703, 0, 1040, 0, 0, 1259, 4145, 0, 0, 84, 0, 864, 0, 390, 3605, 0, + 1902, 0, 0, 0, 0, 0, 0, 611, 2843, 0, 3857, 2178, 458, 2888, 1573, 0, + 0, 0, 1306, 3253, 3974, 0, 0, 0, 0, 459, 2193, 0, 0, 0, 0, 296, 593, + 3501, 0, 2042, 1344, 0, 0, 1960, 0, 0, 0, 106, 1687, 0, 0, 0, 0, 1415, + 3049, 0, 3425, 2390, 474, 191, 526, 1766, 1273, 3915, 3854, 4317, 0, + 2034, 0, 2057, 0, 0, 0, 0, 2799, 2354, 1176, 0, 646, 769, 378, 0, 0, + 2869, 0, 4569, 258, 1184, 0, 1164, 3393, 302, 0, 533, 0, 0, 0, 1108, + 1215, 0, 0, 4317, 0, 1381, 3207, 747, 3861, 862, 1706, 0, 0, 4488, + 3501, 2457, 3982, 1169, 4176, 2786, 325, 0, 0, 0, 0, 325, 4459, 1294, + 0, 0, 0, 0, 3994, 1092, 0, 1841, 141, 0, 1955, 0, 0, 702, 0, 0, 0, 0, + 1721, 731, 0, 4426, 0, 0, 0, 0, 3528, 2312, 0, 1913, 0, 3624, 0, 0, + 4595, 0, 213, 1385, 3550, 0, 2505, 866, 0, 0, 1420, 0, 0, 0, 0, 3689, + 1675, 2282, 860, 0, 1409, 3877, 0, 1178, 0, 0, 0, 1682, 93, 3895, 1958, + 2419, 2159, 0, 808, 0, 0, 2910, 0, 0, 4282, 1230, 0, 3617, 0, 1815, + 3266, 814, 0, 4524, 273, 1946, 0, 164, 900, 4532, 468, 0, 1751, 0, 705, + 2483, 2537, 3052, 0, 0, 258, 1933, 3173, 3150, 503, 2270, 0, 2103, 0, + 198, 0, 3445, 0, 1496, 2453, 2124, 2217, 3079, 0, 0, 0, 0, 0, 0, 1615, + 0, 2513, 1108, 2650, 354, 0, 2968, 3784, 1941, 666, 212, 0, 0, 798, 0, + 0, 0, 2395, 0, 0, 3980, 0, 0, 2203, 2909, 0, 3350, 546, 3442, 3181, + 309, 0, 0, 0, 895, 0, 0, 0, 0, 0, 1900, 971, 1019, 0, 411, 0, 0, 866, + 0, 0, 0, 1293, 0, 3439, 0, 0, 1533, 0, 0, 2881, 1788, 0, 1125, 0, 0, + 429, 0, 1748, 0, 0, 0, 4319, 164, 556, 0, 0, 0, 0, 1997, 0, 3204, 3607, + 1296, 0, 4311, 0, 2304, 0, 634, 2310, 1715, 0, 1423, 0, 0, 0, 2772, 0, + 0, 2263, 0, 4099, 0, 0, 4492, 0, 3760, 0, 0, 3985, 0, 1619, 1754, 701, + 0, 0, 0, 2147, 1867, 4002, 0, 500, 3583, 0, 4429, 1543, 880, 2200, + 2251, 3114, 3487, 0, 327, 2521, 2315, 0, 379, 0, 3547, 0, 1597, 1352, + 2859, 1889, 3869, 2832, 0, 3840, 2399, 0, 1436, 0, 0, 3714, 0, 0, 1453, + 847, 1317, 1968, 0, 1349, 0, 1315, 1488, 0, 2096, 3806, 3787, 773, + 3817, 0, 0, 0, 3681, 0, 459, 1604, 2992, 919, 0, 3961, 4088, 1481, + 2790, 1046, 1714, 0, 0, 4191, 0, 1112, 41, 0, 0, 2431, 3056, 3989, 0, + 1193, 2398, 0, 0, 910, 1375, 3338, 2196, 2957, 1979, 2693, 0, 621, 0, + 3558, 0, 0, 2302, 0, 2823, 0, 0, 0, 1857, 669, 3476, 0, 0, 901, 1443, + 1564, 0, 0, 1597, 1940, 1651, 0, 665, 0, 2079, 2218, 0, 0, 0, 683, 227, + 44, 0, 62, 1804, 0, 0, 955, 0, 0, 0, 1185, 911, 3376, 0, 167, 0, 0, + 4073, 2480, 1856, 1080, 3309, 259, 2304, 2403, 1860, 0, 461, 4064, 0, + 0, 3832, 0, 2025, 3222, 4549, 0, 2978, 0, 2410, 1941, 967, 811, 1177, + 1576, 3907, 151, 1604, 1481, 0, 0, 770, 1226, 0, 4376, 0, 3769, 3294, + 0, 2478, 1695, 1355, 1633, 0, 2001, 0, 0, 2062, 0, 3635, 945, 0, 2739, + 0, 0, 3457, 205, 0, 0, 0, 1949, 0, 0, 3558, 3639, 3328, 0, 4496, 4372, + 2496, 0, 3576, 1538, 1324, 2603, 0, 1829, 0, 0, 1724, 730, 3225, 0, 21, + 4012, 0, 0, 1664, 915, 3142, 0, 1626, 130, 2654, 0, 800, 1944, 2713, 0, + 0, 0, 0, 46, 1600, 0, 0, 0, 1688, 0, 736, 0, 0, 0, 3846, 3757, 0, 2434, + 2046, 0, 3440, 379, 1190, 1652, 4200, 3053, 1613, 1074, 0, 1009, 0, + 1865, 747, 1051, 2458, 0, 2497, 1948, 3768, 0, 3013, 2853, 2351, 0, 0, + 0, 3756, 927, 379, 738, 0, 2366, 0, 1501, 0, 1730, 972, 0, 2278, 3724, + 460, 1521, 365, 1064, 3247, 0, 0, 225, 2505, 3681, 0, 0, 3919, 0, 4397, + 3288, 0, 553, 3288, 0, 0, 0, 3123, 4322, 4263, 3099, 2220, 0, 0, 0, + 2121, 629, 3880, 0, 757, 1133, 1369, 1272, 0, 921, 0, 0, 3740, 0, 0, 0, + 0, 4601, 2527, 2317, 2057, 3097, 1682, 0, 2730, 3992, 2016, 0, 1590, + 2742, 0, 0, 767, 0, 741, 4352, 1980, 973, 0, 1169, 2442, 0, 2416, 3929, + 707, 0, 4296, 3271, 332, 336, 1531, 1691, 1822, 0, 1968, 1104, 0, 1552, + 0, 741, 1220, 2321, 2154, 153, 845, 3512, 2254, 0, 2206, 128, 1078, 0, + 3279, 0, 0, 2613, 0, 0, 1513, 965, 1203, 600, 0, 2219, 0, 1068, 12, + 3981, 281, 1323, 0, 0, 0, 0, 0, 0, 0, 0, 939, 0, 0, 2064, 1926, 0, + 4254, 0, 1591, 624, 868, 445, 237, 0, 3060, 3361, 2534, 1151, 4490, 0, + 1790, 0, 0, 3979, 2782, 0, 1590, 205, 0, 0, 2367, 0, 0, 2141, 0, 2452, + 2780, 257, 0, 0, 1861, 188, 0, 4467, 2451, 1071, 0, 0, 740, 0, 0, 0, + 88, 3031, 0, 3722, 0, 907, 0, 0, 1166, 0, 1080, 0, 276, 1956, 4370, 0, + 4107, 0, 0, 2803, 0, 0, 0, 0, 0, 0, 3671, 1739, 2298, 4281, 0, 0, 2568, + 255, 0, 633, 0, 1319, 2447, 0, 2867, 0, 0, 0, 0, 2905, 0, 0, 150, 3629, + 2848, 0, 2415, 774, 3996, 2528, 0, 764, 0, 523, 1739, 285, 1264, 3771, + 1139, 1928, 0, 1157, 0, 1215, 14, 0, 0, 4006, 2318, 635, 1158, 0, 1361, + 2003, 1780, 3600, 2789, 0, 4147, 164, 0, 2007, 0, 0, 4318, 0, 0, 1269, + 0, 105, 0, 1777, 2771, 2833, 635, 0, 0, 3812, 3703, 1612, 0, 3756, 0, + 0, 0, 1006, 3443, 0, 282, 1047, 4299, 0, 1017, 0, 3034, 0, 0, 1506, + 3101, 3512, 3792, 0, 760, 0, 3688, 0, 2308, 2159, 1861, 0, 0, 0, 0, + 1080, 0, 0, 4521, 0, 4001, 4079, 0, 4030, 3170, 0, 4579, 1478, 0, 1973, + 0, 4459, 0, 0, 1452, 784, 2857, 601, 1776, 1387, 335, 3648, 0, 3988, + 313, 0, 4461, 4071, 1689, 4248, 1366, 703, 3611, 418, 1219, 1605, 2213, + 0, 608, 0, 0, 0, 1782, 1989, 1932, 798, 0, 1058, 719, 3972, 3180, 2025, + 2063, 2114, 890, 0, 0, 1804, 0, 3543, 284, 0, 0, 2378, 0, 0, 93, 0, 0, + 0, 4132, 0, 0, 0, 0, 0, 2700, 0, 0, 2418, 0, 0, 0, 0, 0, 3245, 3854, + 594, 1554, 644, 0, 0, 927, 0, 2352, 1499, 2229, 1508, 1776, 0, 556, 0, + 630, 0, 728, 4137, 0, 2744, 1895, 2229, 448, 2658, 0, 721, 2112, 0, + 1079, 1580, 0, 4521, 4201, 235, 1181, 0, 0, 2208, 0, 515, 2465, 283, 0, + 0, 1515, 4527, 1292, 0, 4041, 282, 1673, 0, 1488, 1608, 0, 0, 0, 2369, + 0, 670, 0, 1211, 0, 1869, 1067, 3397, 2421, 798, 1251, 1908, 0, 65, + 2223, 1725, 4414, 4164, 0, 405, 658, 1820, 247, 1122, 0, 951, 4210, + 3186, 3621, 2264, 960, 0, 0, 1905, 0, 0, 0, 1443, 1638, 0, 424, 1346, + 1671, 0, 1137, 1647, 2450, 4248, 0, 0, 0, 2620, 3655, 4568, 3932, 0, + 949, 0, 0, 1933, 320, 2067, 4000, 0, 692, 855, 0, 0, 2498, 0, 0, 4583, + 2024, 2059, 0, 2889, 4396, 1359, 0, 135, 0, 3969, 0, 1477, 0, 3333, + 2166, 0, 756, 3290, 1991, 145, 2170, 0, 1906, 0, 0, 259, 0, 822, 0, + 4279, 150, 890, 0, 4233, 0, 1052, 0, 0, 3303, 2145, 0, 0, 425, 375, + 1721, 1519, 1730, 0, 0, 0, 0, 0, 1017, 58, 706, 1005, 4525, 2549, 2390, + 3276, 1403, 537, 223, 0, 0, 0, 1733, 4527, 3454, 1114, 0, 4241, 0, + 2135, 769, 128, 0, 3946, 1343, 0, 4263, 2136, 1212, 4265, 4261, 530, + 735, 2117, 0, 0, 581, 0, 2815, 906, 1758, 0, 3129, 3073, 0, 3327, 0, 0, + 3931, 503, 1824, 4, 889, 0, 2857, 391, 2092, 2208, 744, 2095, 0, 0, 0, + 359, 0, 2766, 2348, 0, 2120, 1494, 2406, 0, 1259, 2093, 0, 0, 0, 3896, + 0, 176, 0, 1581, 842, 1522, 1638, 707, 589, 878, 0, 1868, 149, 0, 3581, + 574, 2405, 568, 81, 0, 0, 0, 0, 3528, 2879, 1823, 2890, 0, 0, 2424, + 139, 0, 174, 1862, 1459, 0, 1962, 3290, 80, 4526, 1948, 1763, 0, 3818, + 1866, 0, 3993, 0, 717, 3909, 2296, 1826, 2268, 1944, 1102, 0, 569, + 3764, 2690, 0, 313, 0, 0, 1914, 57, 0, 995, 2930, 0, 952, 1289, 0, 242, + 4506, 0, 3832, 0, 460, 4220, 3387, 2208, 3313, 1124, 407, 2519, 2298, + 1105, 0, 0, 455, 0, 0, 2031, 1509, 4292, 0, 0, 0, 0, 185, 0, 4214, + 1923, 3491, 1658, 2016, 132, 2985, 0, 61, 0, 0, 1828, 42, 2041, 1610, + 0, 3517, 1907, 980, 2363, 1738, 0, 1136, 2113, 0, 0, 1120, 0, 0, 0, 0, + 0, 2462, 0, 4311, 0, 955, 1746, 3531, 0, 0, 0, 3, 0, 1121, 5, 0, 4314, + 3318, 2256, 3662, 2332, 525, 0, 4396, 0, 2107, 0, 0, 1074, 844, 3763, + 3663, 4038, 2112, 0, 0, 0, 2259, 0, 1596, 3632, 0, 0, 405, 0, 0, 723, + 1103, 0, 1998, 2369, 1283, 268, 11, 4592, 2549, 3352, 1886, 0, 1927, + 1365, 2136, 2462, 1894, 0, 2314, 240, 0, 1947, 4180, 3792, 596, 755, + 1058, 1103, 4602, 442, 0, 0, 2096, 1168, 0, 1397, 4195, 515, 0, 0, 0, + 2470, 1552, 926, 2467, 858, 0, 1950, 0, 0, 0, 193, 2472, 0, 0, 824, 0, + 3479, 3079, 2843, 3448, 0, 0, 2158, 0, 0, 2413, 0, 0, 1082, 0, 565, + 4014, 2220, 79, 1687, 423, 1125, 4549, 0, 0, 3657, 479, 0, 0, 2020, 0, + 0, 0, 1541, 4553, 1303, 0, 2271, 981, 0, 2434, 1109, 1885, 0, 2734, + 2175, 2194, 0, 1482, 0, 469, 2939, 469, 659, 0, 1609, 4144, 2188, 33, + 845, 639, 0, 111, 4433, 1628, 741, 1045, 0, 1139, 2142, 2281, 0, 1480, + 47, 0, 3193, 0, 0, 1799, 1370, 1961, 1220, 309, 0, 0, 4466, 427, 3588, + 0, 0, 4380, 0, 3233, 463, 1654, 0, 0, 2223, 2138, 0, 911, 2210, 0, + 1095, 0, 0, 2977, 650, 2091, 0, 1751, 0, 0, 0, 4209, 0, 1331, 3387, + 851, 0, 0, 4249, 2519, 2865, 258, 0, 0, 0, 0, 0, 3316, 2888, 3835, 745, + 0, 2297, 338, 2574, 2218, 0, 0, 851, 0, 208, 0, 0, 0, 0, 1010, 0, 0, + 1353, 4098, 897, 2239, 604, 1519, 1882, 2346, 0, 0, 1015, 641, 4585, + 4445, 1813, 139, 615, 0, 430, 0, 0, 470, 713, 2479, 1276, 3281, 0, + 1819, 0, 0, 0, 2861, 3269, 435, 2283, 0, 889, 236, 3281, 156, 1774, + 431, 0, 1175, 134, 2457, 1777, 3759, 4271, 0, 3603, 39, 1964, 2103, 0, + 0, 1222, 0, 150, 975, 2213, 0, 0, 2021, 0, 855, 0, 0, 4500, 0, 3778, + 3945, 0, 0, 1247, 1037, 0, 0, 0, 0, 1013, 0, 0, 4138, 0, 0, 3957, 128, + 0, 0, 2244, 4317, 0, 1397, 3833, 802, 2300, 4464, 2394, 1624, 988, + 3487, 0, 2247, 183, 0, 2808, 1675, 0, 0, 3377, 179, 1591, 493, 1063, + 4346, 2054, 3795, 547, 2737, 715, 1884, 2459, 1607, 2867, 902, 3040, + 1132, 1383, 2433, 0, 0, 0, 944, 840, 3055, 0, 405, 850, 96, 1558, 2206, + 1638, 4605, 0, 0, 0, 294, 497, 4559, 0, 2089, 242, 595, 1784, 3133, + 189, 0, 3203, 136, 2578, 2632, 3305, 1658, 0, 3959, 0, 0, 0, 534, 0, 0, + 2885, 3002, 0, 1418, 3919, 383, 502, 0, 0, 0, 1792, 3291, 4225, 1705, + 0, 4485, 0, 0, 0, 0, 82, 4013, 1466, 4515, 4590, 2336, 0, 0, 0, 1859, + 0, 27, 4570, 535, 2531, 3794, 0, 1864, 1709, 0, 0, 1552, 3395, 0, 1113, + 0, 684, 497, 0, 0, 1361, 1196, 0, 725, 0, 0, 3309, 4254, 0, 0, 0, 0, 0, + 1962, 1473, 0, 2823, 2320, 1240, 161, 2497, 3593, 1536, 0, 0, 0, 1022, + 2466, 101, 3853, 44, 0, 2082, 3848, 2077, 4494, 139, 1256, 1119, 0, + 3068, 0, 849, 1846, 0, 2221, 0, 0, 4576, 2220, 1376, 2134, 0, 1025, + 127, 4234, 0, 3379, 2597, 3511, 0, 2679, 3274, 1532, 0, 0, 0, 904, 241, + 214, 1983, 0, 1704, 973, 1090, 224, 0, 0, 2656, 1845, 0, 3597, 1823, + 3421, 0, 1983, 376, 0, 1072, 1172, 624, 3149, 0, 0, 0, 0, 2547, 547, + 32, 1601, 0, 1477, 1844, 1161, 0, 317, 3144, 0, 0, 3831, 3266, 3132, + 610, 0, 963, 2286, 3748, 0, 508, 640, 2623, 554, 210, 0, 0, 2263, 0, + 1877, 1721, 3160, 3678, 451, 8, 166, 0, 3517, 675, 0, 0, 327, 342, 0, + 0, 2149, 0, 0, 0, 655, 0, 3571, 1965, 0, 3866, 606, 440, 25, 3878, + 3505, 0, 384, 0, 0, 0, 2411, 0, 0, 0, 438, 2296, 922, 1427, 0, 1253, + 1008, 4393, 1530, 0, 0, 1524, 356, 487, 0, 0, 4369, 174, 0, 0, 0, 897, + 2605, 0, 1614, 0, 0, 967, 0, 0, 2377, 1005, 0, 914, 2710, 1448, 0, + 2464, 0, 0, 1440, 0, 3087, 0, 1631, 2861, 1386, 4535, 531, 0, 0, 360, + 0, 1632, 121, 0, 0, 2437, 3858, 0, 4285, 2538, 0, 0, 0, 843, 4509, 0, + 3016, 773, 0, 2104, 3098, 732, 0, 560, 124, 1935, 4469, 0, 0, 2166, 0, + 335, 0, 1929, 653, 1919, 0, 0, 0, 0, 0, 0, 0, 3211, 0, 1073, 0, 0, + 3078, 0, 635, 0, 3786, 0, 759, 2127, 727, 183, 0, 421, 0, 698, 1156, + 4324, 0, 0, 2618, 840, 1044, 0, 1211, 162, 3311, 3735, 4461, 2226, 0, + 0, 2548, 650, 1738, 2982, 0, 3445, 0, 4277, 690, 3876, 0, 1077, 3702, + 142, 897, 1857, 0, 0, 0, 2630, 0, 1651, 4136, 559, 1855, 0, 1095, 751, + 0, 2118, 547, 2408, 1667, 817, 0, 0, 1699, 2948, 972, 462, 4093, 1628, + 4449, 55, 3590, 1558, 1837, 788, 0, 1708, 44, 0, 0, 0, 2276, 0, 1800, + 1722, 911, 0, 4486, 1559, 3097, 821, 2046, 496, 2530, 366, 0, 2039, 23, + 3721, 3117, 0, 217, 421, 454, 2646, 2174, 1038, 0, 1500, 162, 0, 248, + 898, 867, 1534, 4285, 0, 3567, 0, 1365, 0, 0, 345, 3529, 66, 134, 2188, + 2086, 2040, 4145, 1300, 1628, 3988, 368, 875, 1311, 0, 1558, 2703, 696, + 0, 3224, 460, 361, 2325, 3605, 0, 1143, 1166, 0, 0, 0, 1353, 2516, + 1202, 2270, 3700, 1943, 1290, 0, 2455, 0, 0, 908, 0, 0, 2602, 685, + 2142, 2471, 98, 672, 839, 0, 0, 0, 0, 2933, 0, 157, 3160, 0, 0, 399, + 17, 0, 400, 1588, 1118, 54, 337, 0, 1206, 42, 1607, 1285, 2265, 0, + 2084, 0, 414, 2431, 760, 3331, 0, 0, 3833, 1891, 1512, 0, 2921, 0, 162, + 0, 38, 4281, 0, 3224, 0, 3394, 0, 0, 595, 2583, 820, 1347, 0, 558, 0, + 0, 0, 0, 2433, 3845, 4095, 2861, 3386, 2212, 0, 416, 0, 1467, 1171, 0, + 2969, 0, 2101, 0 }; static size_t @@ -2904,15 +2910,15 @@ static size_t keysym_name_perfect_hash(const char *key) { return ( - keysym_name_G[keysym_name_hash_f(key, "5XIszGSHrUVRAzLN0l8MLLfHRGGeJyyt")] + - keysym_name_G[keysym_name_hash_f(key, "OmXqMt6YLQmWcqQWNXDALosGVTbkNhjb")] + keysym_name_G[keysym_name_hash_f(key, "zzGJdgx3rzfKID5pIiYCv5fKP0eBmaQz")] + + keysym_name_G[keysym_name_hash_f(key, "ER55SF79aGq9YpjBoPvcuXhlBtviaRor")] ) % 4622; } struct name_keysym { xkb_keysym_t keysym; - uint32_t offset; + uint16_t offset; }; static const struct name_keysym name_to_keysym[] = { @@ -7942,3 +7948,176 @@ static const struct name_keysym keysym_to_name[] = { { 0x1008ffb7, 30561 }, /* XF86RotationLockToggle */ { 0x1008ffb8, 28288 }, /* XF86FullScreen */ }; + +#define DEPRECATED_KEYSYM 0xffff + +struct deprecated_keysym { + xkb_keysym_t keysym; + uint16_t offset; + /* Explicit deprecated aliases start index & count */ + uint8_t explicit_index; + uint8_t explicit_count; +}; + +static const struct deprecated_keysym deprecated_keysyms[] = { + { 0x00000027, 934 , 0, 0 }, /* Reference: apostrophe. Deprecated: quoteright */ + { 0x00000060, 13381 , 0, 0 }, /* Reference: grave. Deprecated: quoteleft */ + { 0x000000ab, 14464 , 0, 0 }, /* Reference: guillemetleft. Deprecated: guillemotleft */ + { 0x000000ba, 21008 , 0, 0 }, /* Reference: ordmasculine. Deprecated: masculine */ + { 0x000000bb, 14478 , 0, 0 }, /* Reference: guillemetright. Deprecated: guillemotright */ + { 0x000000d0, 12179 , 0, 0 }, /* Reference: ETH. Deprecated: Eth */ + { 0x000000d8, 21453 , 0, 0 }, /* Reference: Oslash. Deprecated: Ooblique */ + { 0x000000de, 25656 , 0, 0 }, /* Reference: THORN. Deprecated: Thorn */ + { 0x000000f8, 21460 , 0, 0 }, /* Reference: oslash. Deprecated: ooblique */ + { 0x000003a2, 19252 , 0, 0 }, /* Reference: kra. Deprecated: kappa */ + { 0x000004a5, 18348 , 0, 0 }, /* Reference: kana_conjunctive. Deprecated: kana_middledot */ + { 0x000004af, 18786 , 0, 0 }, /* Reference: kana_tsu. Deprecated: kana_tu */ + { 0x000004c1, 18308 , 0, 0 }, /* Reference: kana_CHI. Deprecated: kana_TI */ + { 0x000004c2, 18777 , 0, 0 }, /* Reference: kana_TSU. Deprecated: kana_TU */ + { 0x000004cc, 18379 , 0, 0 }, /* Reference: kana_FU. Deprecated: kana_HU */ + { 0x000005e7, 1282 , 0, 0 }, /* Reference: Arabic_ha. Deprecated: Arabic_heh */ + { 0x000006a4, 26369 , 0, 0 }, /* Reference: Ukrainian_ie. Deprecated: Ukranian_je */ + { 0x000006a6, 26344 , 0, 0 }, /* Reference: Ukrainian_i. Deprecated: Ukranian_i */ + { 0x000006a7, 26395 , 0, 0 }, /* Reference: Ukrainian_yi. Deprecated: Ukranian_yi */ + { 0x000006a8, 9574 , 0, 0 }, /* Reference: Cyrillic_je. Deprecated: Serbian_je */ + { 0x000006a9, 9713 , 0, 0 }, /* Reference: Cyrillic_lje. Deprecated: Serbian_lje */ + { 0x000006aa, 9739 , 0, 0 }, /* Reference: Cyrillic_nje. Deprecated: Serbian_nje */ + { 0x000006af, 9068 , 0, 0 }, /* Reference: Cyrillic_dzhe. Deprecated: Serbian_dze */ + { 0x000006b4, 26356 , 0, 0 }, /* Reference: Ukrainian_IE. Deprecated: Ukranian_JE */ + { 0x000006b6, 26332 , 0, 0 }, /* Reference: Ukrainian_I. Deprecated: Ukranian_I */ + { 0x000006b7, 26382 , 0, 0 }, /* Reference: Ukrainian_YI. Deprecated: Ukranian_YI */ + { 0x000006b8, 9562 , 0, 0 }, /* Reference: Cyrillic_JE. Deprecated: Serbian_JE */ + { 0x000006b9, 9700 , 0, 0 }, /* Reference: Cyrillic_LJE. Deprecated: Serbian_LJE */ + { 0x000006ba, 9726 , 0, 0 }, /* Reference: Cyrillic_NJE. Deprecated: Serbian_NJE */ + { 0x000006bf, 9054 , 0, 0 }, /* Reference: Cyrillic_DZHE. Deprecated: Serbian_DZE */ + { 0x000007a5, 13841 , 0, 0 }, /* Reference: Greek_IOTAdieresis. Deprecated: Greek_IOTAdiaeresis */ + { 0x000008a2, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: topleftradical */ + { 0x000008a3, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: horizconnector */ + { 0x000008a6, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: vertconnector */ + { 0x00000aac, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: signifblank */ + { 0x00000abc, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: leftanglebracket */ + { 0x00000abd, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: decimalpoint */ + { 0x00000abe, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: rightanglebracket */ + { 0x00000aca, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: signaturemark */ + { 0x00000acc, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: leftopentriangle */ + { 0x00000acd, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: rightopentriangle */ + { 0x00000ace, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: emopencircle */ + { 0x00000acf, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: emopenrectangle */ + { 0x00000adb, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: filledrectbullet */ + { 0x00000adc, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: filledlefttribullet */ + { 0x00000add, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: filledrighttribullet */ + { 0x00000ade, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: emfilledcircle */ + { 0x00000adf, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: emfilledrect */ + { 0x00000ae0, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: enopencircbullet */ + { 0x00000ae1, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: enopensquarebullet */ + { 0x00000ae2, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: openrectbullet */ + { 0x00000ae3, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: opentribulletup */ + { 0x00000ae4, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: opentribulletdown */ + { 0x00000ae5, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: openstar */ + { 0x00000ae6, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: enfilledcircbullet */ + { 0x00000ae7, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: enfilledsqbullet */ + { 0x00000ae8, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: filledtribulletup */ + { 0x00000ae9, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: filledtribulletdown */ + { 0x00000aea, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: leftpointer */ + { 0x00000aeb, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: rightpointer */ + { 0x00000ba3, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: leftcaret */ + { 0x00000ba6, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: rightcaret */ + { 0x00000ba8, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: downcaret */ + { 0x00000ba9, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: upcaret */ + { 0x00000bc0, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: overbar */ + { 0x00000bc3, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: upshoe */ + { 0x00000bc6, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: underbar */ + { 0x00000bd6, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: downshoe */ + { 0x00000bd8, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: rightshoe */ + { 0x00000bda, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: leftshoe */ + { 0x00000ce1, 16255 , 0, 0 }, /* Reference: hebrew_bet. Deprecated: hebrew_beth */ + { 0x00000ce2, 16436 , 0, 0 }, /* Reference: hebrew_gimel. Deprecated: hebrew_gimmel */ + { 0x00000ce3, 16290 , 0, 0 }, /* Reference: hebrew_dalet. Deprecated: hebrew_daleth */ + { 0x00000ce6, 16721 , 0, 0 }, /* Reference: hebrew_zain. Deprecated: hebrew_zayin */ + { 0x00000ce7, 16278 , 0, 0 }, /* Reference: hebrew_chet. Deprecated: hebrew_het */ + { 0x00000ce8, 16652 , 0, 0 }, /* Reference: hebrew_tet. Deprecated: hebrew_teth */ + { 0x00000cf1, 16576 , 0, 0 }, /* Reference: hebrew_samech. Deprecated: hebrew_samekh */ + { 0x00000cf5, 16402 , 0, 0 }, /* Reference: hebrew_finalzade. Deprecated: hebrew_finalzadi */ + { 0x00000cf6, 16697 , 0, 0 }, /* Reference: hebrew_zade. Deprecated: hebrew_zadi */ + { 0x00000cf7, 16552 , 0, 0 }, /* Reference: hebrew_qoph. Deprecated: hebrew_kuf */ + { 0x00000cfa, 16641 , 0, 0 }, /* Reference: hebrew_taw. Deprecated: hebrew_taf */ + { 0x00000dde, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: Thai_maihanakat_maitho */ + { 0x00000eff, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: Korean_Won */ + { 0x0000fe8a, 11150 , 0, 0 }, /* Reference: dead_schwa. Deprecated: dead_small_schwa */ + { 0x0000fe8b, 11139 , 0, 0 }, /* Reference: dead_SCHWA. Deprecated: dead_capital_schwa */ + { 0x0000ff20, 19955 , 0, 0 }, /* Reference: Multi_key. Deprecated: SunCompose */ + { 0x0000ff37, 8654 , 0, 0 }, /* Reference: Codeinput. Deprecated: Kanji_Bangou, Hangul_Codeinput */ + { 0x0000ff3c, 23169 , 0, 0 }, /* Reference: SingleCandidate. Deprecated: Hangul_SingleCandidate */ + { 0x0000ff3d, 19965 , 0, 0 }, /* Reference: MultipleCandidate. Deprecated: Zen_Koho, Hangul_MultipleCandidate */ + { 0x0000ff3e, 22257 , 0, 0 }, /* Reference: PreviousCandidate. Deprecated: Mae_Koho, Hangul_PreviousCandidate */ + { 0x0000ff55, 22281 , 0, 0 }, /* Reference: Prior. Deprecated: Page_Up, SunPageUp */ + { 0x0000ff56, 20167 , 0, 0 }, /* Reference: Next. Deprecated: Page_Down, SunPageDown */ + { 0x0000ff61, 22275 , 0, 0 }, /* Reference: Print. Deprecated: SunPrint_Screen */ + { 0x0000ff65, 26514 , 0, 0 }, /* Reference: Undo. Deprecated: SunUndo */ + { 0x0000ff66, 22483 , 0, 0 }, /* Reference: Redo. Deprecated: SunAgain */ + { 0x0000ff68, 12646 , 0, 0 }, /* Reference: Find. Deprecated: SunFind */ + { 0x0000ff69, 8489 , 0, 0 }, /* Reference: Cancel. Deprecated: SunStop */ + { 0x0000ff7e, 19891 , 0, 1 }, /* Reference: Mode_switch. Non deprecated aliases: script_switch, ISO_Group_Shift, kana_switch, Arabic_switch, Greek_switch, Hebrew_switch, Hangul_switch. Deprecated: SunAltGraph */ + { 0x0000ff9a, 19187 , 0, 0 }, /* Reference: KP_Prior. Deprecated: KP_Page_Up */ + { 0x0000ff9b, 19155 , 0, 0 }, /* Reference: KP_Next. Deprecated: KP_Page_Down */ + { 0x0000ffc8, 12281 , 0, 0 }, /* Reference: F11. Deprecated: L1 */ + { 0x0000ffc9, 12285 , 0, 0 }, /* Reference: F12. Deprecated: L2 */ + { 0x0000ffca, 12289 , 0, 0 }, /* Reference: F13. Deprecated: L3 */ + { 0x0000ffcb, 12293 , 0, 0 }, /* Reference: F14. Deprecated: L4 */ + { 0x0000ffcc, 12297 , 0, 0 }, /* Reference: F15. Deprecated: L5 */ + { 0x0000ffcd, 12301 , 0, 0 }, /* Reference: F16. Deprecated: L6 */ + { 0x0000ffce, 12305 , 0, 0 }, /* Reference: F17. Deprecated: L7 */ + { 0x0000ffcf, 12309 , 0, 0 }, /* Reference: F18. Deprecated: L8 */ + { 0x0000ffd0, 12313 , 0, 0 }, /* Reference: F19. Deprecated: L9 */ + { 0x0000ffd1, 12320 , 0, 0 }, /* Reference: F20. Deprecated: L10 */ + { 0x0000ffd2, 12324 , 0, 0 }, /* Reference: F21. Deprecated: R1 */ + { 0x0000ffd3, 12328 , 0, 0 }, /* Reference: F22. Deprecated: R2 */ + { 0x0000ffd4, 12332 , 0, 0 }, /* Reference: F23. Deprecated: R3 */ + { 0x0000ffd5, 12336 , 0, 0 }, /* Reference: F24. Deprecated: R4 */ + { 0x0000ffd6, 12340 , 0, 0 }, /* Reference: F25. Deprecated: R5 */ + { 0x0000ffd7, 12344 , 0, 0 }, /* Reference: F26. Deprecated: R6 */ + { 0x0000ffd8, 12348 , 0, 0 }, /* Reference: F27. Deprecated: R7 */ + { 0x0000ffd9, 12352 , 0, 0 }, /* Reference: F28. Deprecated: R8 */ + { 0x0000ffda, 12356 , 0, 0 }, /* Reference: F29. Deprecated: R9 */ + { 0x0000ffdb, 12363 , 0, 0 }, /* Reference: F30. Deprecated: R10 */ + { 0x0000ffdc, 12367 , 0, 0 }, /* Reference: F31. Deprecated: R11 */ + { 0x0000ffdd, 12371 , 0, 0 }, /* Reference: F32. Deprecated: R12 */ + { 0x0000ffde, 12375 , 0, 0 }, /* Reference: F33. Deprecated: R13 */ + { 0x0000ffdf, 12379 , 0, 0 }, /* Reference: F34. Deprecated: R14 */ + { 0x0000ffe0, 12383 , 0, 0 }, /* Reference: F35. Deprecated: R15 */ + { 0x0100055b, 2048 , 0, 0 }, /* Reference: Armenian_accent. Deprecated: Armenian_shesht */ + { 0x0100055c, 2287 , 0, 0 }, /* Reference: Armenian_exclam. Deprecated: Armenian_amanak */ + { 0x0100055d, 2869 , 0, 0 }, /* Reference: Armenian_separation_mark. Deprecated: Armenian_but */ + { 0x0100055e, 2779 , 0, 0 }, /* Reference: Armenian_question. Deprecated: Armenian_paruyk */ + { 0x01000589, 2327 , 0, 0 }, /* Reference: Armenian_full_stop. Deprecated: Armenian_verjaket */ + { 0x0100058a, 2448 , 0, 0 }, /* Reference: Armenian_hyphen. Deprecated: Armenian_yentamna */ + { 0x010006cc, 12505 , 0, 0 }, /* Reference: Farsi_yeh. Deprecated: Arabic_farsi_yeh */ + { 0x01002247, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: notapproxeq */ + { 0x01002248, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: approxeq */ + { 0x100000a8, 17054 , 0, 0 }, /* Reference: hpmute_acute. Deprecated: mute_acute */ + { 0x100000a9, 17121 , 0, 0 }, /* Reference: hpmute_grave. Deprecated: mute_grave */ + { 0x100000aa, 17067 , 0, 0 }, /* Reference: hpmute_asciicircum. Deprecated: mute_asciicircum */ + { 0x100000ab, 17104 , 0, 0 }, /* Reference: hpmute_diaeresis. Deprecated: mute_diaeresis */ + { 0x100000ac, 17086 , 0, 0 }, /* Reference: hpmute_asciitilde. Deprecated: mute_asciitilde */ + { 0x100000af, 17011 , 0, 0 }, /* Reference: hplira. Deprecated: lira */ + { 0x100000be, 16957 , 0, 0 }, /* Reference: hpguilder. Deprecated: guilder */ + { 0x100000ee, 17158 , 0, 0 }, /* Reference: hpYdiaeresis. Deprecated: hpIO, IO */ + { 0x100000f6, 17018 , 0, 0 }, /* Reference: hplongminus. Deprecated: longminus */ + { 0x100000fc, 16911 , 0, 0 }, /* Reference: hpblock. Deprecated: block */ + { 0x1000ff6c, 17134 , 0, 0 }, /* Reference: hpReset. Deprecated: Reset */ + { 0x1000ff6d, 17142 , 0, 0 }, /* Reference: hpSystem. Deprecated: System */ + { 0x1000ff6e, 17151 , 0, 0 }, /* Reference: hpUser. Deprecated: User */ + { 0x1000ff6f, 16919 , 0, 0 }, /* Reference: hpClearLine. Deprecated: ClearLine */ + { 0x1000ff70, 16980 , 0, 0 }, /* Reference: hpInsertLine. Deprecated: InsertLine */ + { 0x1000ff71, 16944 , 0, 0 }, /* Reference: hpDeleteLine. Deprecated: DeleteLine */ + { 0x1000ff72, 16967 , 0, 0 }, /* Reference: hpInsertChar. Deprecated: InsertChar */ + { 0x1000ff73, 16931 , 0, 0 }, /* Reference: hpDeleteChar. Deprecated: DeleteChar */ + { 0x1000ff74, 16901 , 0, 0 }, /* Reference: hpBackTab. Deprecated: BackTab */ + { 0x1000ff75, 16998 , 0, 0 }, /* Reference: hpKP_BackTab. Deprecated: KP_BackTab */ + { 0x1000ff76, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: Ext16bit_L */ + { 0x1000ff77, DEPRECATED_KEYSYM, 0, 0 }, /* Deprecated: Ext16bit_R */ +}; + +static const uint32_t explicit_deprecated_aliases[] = { + 24029, +}; diff --git a/src/messages-codes.h b/src/messages-codes.h index 3be18db0..e6637266 100644 --- a/src/messages-codes.h +++ b/src/messages-codes.h @@ -56,6 +56,10 @@ enum xkb_message_code { XKB_WARNING_CONFLICTING_KEY_TYPE_MAP_ENTRY = 266, /** Warn if using an undefined key type */ XKB_WARNING_UNDEFINED_KEY_TYPE = 286, + /** A keysym has been deprecated: consider using an alternative keysym */ + XKB_WARNING_DEPRECATED_KEYSYM = 301, + /** A keysym name has been deprecated: use the corresponding canonical name instead */ + XKB_WARNING_DEPRECATED_KEYSYM_NAME = 302, /** Warn if a group name was defined for group other than the first one */ XKB_WARNING_NON_BASE_GROUP_NAME = 305, /** Warn when a shift level is not supported */ diff --git a/src/xkbcomp/expr.c b/src/xkbcomp/expr.c index 2459713f..34b70a59 100644 --- a/src/xkbcomp/expr.c +++ b/src/xkbcomp/expr.c @@ -710,8 +710,11 @@ ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr, if (expr->expr.op == EXPR_IDENT) { const char *str = xkb_atom_text(ctx, expr->ident.ident); *sym_rtrn = xkb_keysym_from_name(str, 0); - if (*sym_rtrn != XKB_KEY_NoSymbol) + if (*sym_rtrn != XKB_KEY_NoSymbol) { + check_deprecated_keysyms(log_warn, ctx, ctx, + *sym_rtrn, str, str, "%s", "\n"); return true; + } } if (!ExprResolveInteger(ctx, expr, &val)) @@ -719,8 +722,8 @@ ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr, if (val < XKB_KEYSYM_MIN) { log_warn(ctx, XKB_WARNING_UNRECOGNIZED_KEYSYM, - "unrecognized keysym \"-0x%x\" (%d)\n", - (unsigned int) -val, val); + "unrecognized keysym \"-0x%x\" (%d)\n", + (unsigned int) -val, val); return false; } @@ -731,16 +734,17 @@ ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr, } if (val <= XKB_KEYSYM_MAX) { + check_deprecated_keysyms(log_warn, ctx, ctx, val, NULL, val, "0x%x", "\n"); log_warn(ctx, XKB_WARNING_NUMERIC_KEYSYM, - "numeric keysym \"0x%x\" (%d)", - (unsigned int) val, val); + "numeric keysym \"0x%x\" (%d)", + (unsigned int) val, val); *sym_rtrn = (xkb_keysym_t) val; return true; } log_warn(ctx, XKB_WARNING_UNRECOGNIZED_KEYSYM, - "unrecognized keysym \"0x%x\" (%d)\n", - (unsigned int) val, val); + "unrecognized keysym \"0x%x\" (%d)\n", + (unsigned int) val, val); return false; } diff --git a/src/xkbcomp/parser.y b/src/xkbcomp/parser.y index 0dafedd9..02d1e20f 100644 --- a/src/xkbcomp/parser.y +++ b/src/xkbcomp/parser.y @@ -59,7 +59,7 @@ _xkbcommon_error(struct parser_param *param, const char *msg) } static bool -resolve_keysym(const char *name, xkb_keysym_t *sym_rtrn) +resolve_keysym(struct parser_param *param, const char *name, xkb_keysym_t *sym_rtrn) { xkb_keysym_t sym; @@ -76,6 +76,8 @@ resolve_keysym(const char *name, xkb_keysym_t *sym_rtrn) sym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS); if (sym != XKB_KEY_NoSymbol) { *sym_rtrn = sym; + check_deprecated_keysyms(parser_warn, param, param->ctx, + sym, name, name, "%s", ""); return true; } @@ -726,7 +728,7 @@ KeySyms : OBRACE KeySymList CBRACE KeySym : IDENT { - if (!resolve_keysym($1, &$$)) { + if (!resolve_keysym(param, $1, &$$)) { parser_warn( param, XKB_WARNING_UNRECOGNIZED_KEYSYM, @@ -750,12 +752,15 @@ KeySym : IDENT $$ = XKB_KEY_NoSymbol; } /* Special case for digits 0..9 */ - else if ($1 < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */ + else if ($1 < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */ $$ = XKB_KEY_0 + (xkb_keysym_t) $1; } else { if ($1 <= XKB_KEYSYM_MAX) { $$ = (xkb_keysym_t) $1; + check_deprecated_keysyms( + parser_warn, param, param->ctx, + $$, NULL, $$, "0x%"PRIx32, ""); } else { parser_warn( param, XKB_WARNING_UNRECOGNIZED_KEYSYM, diff --git a/test/keysym.c b/test/keysym.c index 190c9c5d..906af106 100644 --- a/test/keysym.c +++ b/test/keysym.c @@ -169,6 +169,26 @@ test_keysym(xkb_keysym_t keysym, const char *expected) return streq(s, expected); } +static bool +test_deprecated(xkb_keysym_t keysym, const char *name, + bool expected_deprecated, const char *expected_reference) +{ + const char *reference; + bool deprecated = xkb_keysym_is_deprecated(keysym, name, &reference); + + fprintf(stderr, "Expected keysym %#x -> deprecated: %d, reference: %s\n", + keysym, expected_deprecated, expected_reference); + fprintf(stderr, "Received keysym %#x -> deprecated: %d, reference: %s\n", + keysym, deprecated, reference); + + return deprecated == expected_deprecated && + ( + (reference == NULL && expected_reference == NULL) || + (reference != NULL && expected_reference != NULL && + strcmp(reference, expected_reference) == 0) + ); +} + static int test_utf8(xkb_keysym_t keysym, const char *expected) { @@ -567,7 +587,7 @@ main(void) assert(test_string("0x09abcdef", 0x09abcdef)); assert(test_string("0x01000100", XKB_KEYSYM_UNICODE_MIN)); /* Min Unicode. */ assert(test_string("0x0110ffff", XKB_KEYSYM_UNICODE_MAX)); /* Max Unicode. */ - assert(test_string(STRINGIFY2(XKB_KEYSYM_MAX), XKB_KEYSYM_MAX)); /* Max keysym. */ + assert(test_string(STRINGIFY2(XKB_KEYSYM_MAX), XKB_KEYSYM_MAX)); /* Max keysym. */ assert(test_string("0x20000000", XKB_KEY_NoSymbol)); assert(test_string("0xffffffff", XKB_KEY_NoSymbol)); assert(test_string("0x100000000", XKB_KEY_NoSymbol)); @@ -621,6 +641,38 @@ main(void) assert(test_keysym(XKB_KEYSYM_MAX + 1, "Invalid")); assert(test_keysym(0xffffffff, "Invalid")); + /* Name is assumed to be correct but we provide garbage */ + const char garbage_name[] = "bla bla bla"; + assert(test_deprecated(XKB_KEY_NoSymbol, NULL, false, NULL)); + assert(test_deprecated(XKB_KEY_NoSymbol, "NoSymbol", false, NULL)); + assert(test_deprecated(XKB_KEY_A, "A", false, NULL)); + assert(test_deprecated(XKB_KEY_A, NULL, false, NULL)); + assert(test_deprecated(XKB_KEY_A, garbage_name, false, NULL)); + assert(test_deprecated(XKB_KEY_ETH, "ETH", false, "ETH")); + assert(test_deprecated(XKB_KEY_ETH, "Eth", true, "ETH")); + assert(test_deprecated(XKB_KEY_ETH, garbage_name, true, "ETH")); + assert(test_deprecated(XKB_KEY_topleftradical, NULL, true, NULL)); + assert(test_deprecated(XKB_KEY_topleftradical, "topleftradical", true, NULL)); + assert(test_deprecated(XKB_KEY_topleftradical, garbage_name, true, NULL)); + /* Mixed deprecated and not deprecated aliases */ + assert(test_deprecated(XKB_KEY_Mode_switch, NULL, false, "Mode_switch")); + assert(test_deprecated(XKB_KEY_Mode_switch, "Mode_switch", false, "Mode_switch")); + assert(test_deprecated(XKB_KEY_Mode_switch, garbage_name, false, "Mode_switch")); + assert(test_deprecated(XKB_KEY_ISO_Group_Shift, NULL, false, "Mode_switch")); + assert(test_deprecated(XKB_KEY_ISO_Group_Shift, "ISO_Group_Shift", false, "Mode_switch")); + assert(test_deprecated(XKB_KEY_ISO_Group_Shift, garbage_name, false, "Mode_switch")); + assert(test_deprecated(XKB_KEY_SunAltGraph, NULL, false, "Mode_switch")); + assert(test_deprecated(XKB_KEY_SunAltGraph, "SunAltGraph", true, "Mode_switch")); + assert(test_deprecated(XKB_KEY_SunAltGraph, garbage_name, false, "Mode_switch")); + /* Unicode is never deprecated */ + assert(test_deprecated(0x0100250C, "U250C", false, NULL)); + assert(test_deprecated(0x0100250C, "0x0100250C", false, NULL)); + assert(test_deprecated(XKB_KEYSYM_MAX, NULL, false, NULL)); + assert(test_deprecated(XKB_KEYSYM_MAX, NULL, false, NULL)); + /* Invalid keysym */ + assert(test_deprecated(0xffffffff, NULL, false, NULL)); + assert(test_deprecated(0xffffffff, NULL, false, NULL)); + assert(test_casestring("Undo", 0xFF65)); assert(test_casestring("UNDO", 0xFF65)); assert(test_casestring("A", 0x61)); diff --git a/tools/messages.c b/tools/messages.c index 8fafd158..d9823212 100644 --- a/tools/messages.c +++ b/tools/messages.c @@ -58,6 +58,8 @@ static const struct xkb_message_entry xkb_messages[] = { {XKB_ERROR_INVALID_SET_DEFAULT_STATEMENT, "Invalid set default statement"}, {XKB_WARNING_CONFLICTING_KEY_TYPE_MAP_ENTRY, "Conflicting key type map entry"}, {XKB_WARNING_UNDEFINED_KEY_TYPE, "Undefined key type"}, + {XKB_WARNING_DEPRECATED_KEYSYM, "Deprecated keysym"}, + {XKB_WARNING_DEPRECATED_KEYSYM_NAME, "Deprecated keysym name"}, {XKB_WARNING_NON_BASE_GROUP_NAME, "Non base group name"}, {XKB_ERROR_UNSUPPORTED_SHIFT_LEVEL, "Unsupported shift level"}, {XKB_ERROR_INCLUDED_FILE_NOT_FOUND, "Included file not found"},