From 2b994a7a89eba4f5e8fb8c769ecfb000caccbd5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Thu, 8 Oct 2026 21:55:57 +0300 Subject: [PATCH] v3.23.8: the command-grouped TERMINAL RESPONSE result list The step editor's result select offers the full TS 102 223 8.12.0 list; the spec's applicability table (Tables 6.1/6.2/6.3, "Proactive commands versus possible terminal response") now groups it by the selected command: the command-relevant values first (an "relevant for "), the rest after ("all other results"). The grouping is ordering-only - nothing is hidden, the manual hex entry covers everything, and ANY (the drain's respond/first too) stays a flat list, so a stored result always matches an option and real-card deviations remain reachable. TR_RESULT_BY_COMMAND is parsed from the pinned PDF (41 commands) and pinned by frontend/tests/tr_result_by_command.json; trCommandCode() resolves the editor's command names to their type codes (the first code per name, matching testCommandOptions) and testFormSelect gained the optgroup support. Tests: the map vs the parsed fixture, the grouping and the union (nothing lost), the optgroup rendering and the call-site pin. 861 frontend + 842 Python; sw cache simple-v421. --- docs/test-scripts.md | 6 +- frontend/index.html | 108 +++++++++++++++++++++-- frontend/sw.js | 2 +- frontend/tests/testscripts.test.js | 6 +- frontend/tests/tr_result_by_command.json | 46 ++++++++++ frontend/tests/tr_results.test.js | 65 +++++++++++++- pyproject.toml | 2 +- pysim_simple_server/server.py | 2 +- 8 files changed, 220 insertions(+), 17 deletions(-) create mode 100644 frontend/tests/tr_result_by_command.json diff --git a/docs/test-scripts.md b/docs/test-scripts.md index 49d6383..947bd0c 100644 --- a/docs/test-scripts.md +++ b/docs/test-scripts.md @@ -473,7 +473,11 @@ identities, **Result**, Duration, Text string, Item identifier, …): - `result` - a script alias or the two-digit hex value. The editor offers the **full TS 102 223 §8.12.0 list** (`00`–`3F`), labelled ` - ` where an alias exists, else ` - `, plus a - **manual** hex entry for any other value. The aliases: + **manual** hex entry for any other value. With a command selected (other + than `ANY`) the list is **grouped** by the spec's applicability table + (TS 102 223 Tables 6.1/6.2/6.3, "proactive commands versus possible terminal + response"): the command-relevant values first, the rest after - nothing is + hidden, the manual entry covers everything. The aliases: `ok`=00, `partial`=01, `missing`=02, `modified`=07, `cancel`=10, `back`=11, `timeout`=12, `refused`=22, `not_understood`=32 (and `no_response`=12, kept for compatibility only). diff --git a/frontend/index.html b/frontend/index.html index 76743c1..9ed45dd 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1905,7 +1905,7 @@ // ===== Version ===== // Single source of truth for the PWA version: shown in the header and used // by the server version check in pysimConnect(). -const SIMPLE_VERSION = '3.23.7'; +const SIMPLE_VERSION = '3.23.8'; document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION; // ===== view history (the browser Back/Forward buttons) ===== @@ -8028,6 +8028,58 @@ const TR_RESULT_ADD_INFO = [ {v: '0A', name: 'No NAA active'}, ]; +// TS 102 223 v18.3.0 Tables 6.1/6.2 ('Proactive commands versus possible +// terminal response'): the result values the spec lists for each proactive +// command, keyed by the command type code. The step editor GROUPS the result +// list with it - the command-relevant values first, the rest after; nothing +// is hidden (the manual entry covers everything). The fixture +// frontend/tests/tr_result_by_command.json is the pinned copy of the parsed +// table; some entries follow the printed table even where it looks surprising +// (e.g. the icon result listed for REFRESH). +const TR_RESULT_BY_COMMAND = { + '01': ['00', '01', '02', '03', '04', '08', '20', '30', '31', '32', '33', '36', '3C'], + '02': ['00', '01', '02', '20', '30', '31', '32', '33', '36'], + '03': ['00', '01', '02', '20', '30', '31', '32', '33', '36'], + '04': ['00', '01', '02', '20', '30', '31', '32', '33', '36'], + '05': ['00', '01', '02', '20', '30', '31', '32', '33', '36'], + '10': ['00', '01', '02', '04', '05', '10', '14', '20', '21', '22', '23', '25', '30', '31', '32', '33', '34', '36', '39', '3C'], + '14': ['00', '01', '02', '04', '10', '20', '30', '31', '32', '33', '36', '3C'], + '15': ['00', '01', '02', '20', '21', '26', '30', '31', '32', '33', '3C'], + '20': ['00', '01', '02', '04', '09', '10', '20', '30', '31', '32', '33', '36', '3C'], + '21': ['00', '01', '02', '04', '10', '11', '12', '20', '30', '31', '32', '33', '36', '3C'], + '22': ['00', '01', '02', '04', '10', '11', '12', '13', '20', '30', '31', '32', '33', '36', '3C'], + '23': ['00', '01', '02', '04', '10', '11', '12', '13', '20', '30', '31', '32', '33', '36', '3C'], + '24': ['00', '01', '02', '04', '10', '11', '12', '13', '20', '30', '31', '32', '33', '36', '3C'], + '25': ['00', '01', '02', '04', '20', '30', '31', '32', '33', '36'], + '26': ['00', '01', '02', '06', '20', '30', '31', '32', '33', '36'], + '27': ['00', '01', '02', '20', '24', '30', '31', '32', '33', '36'], + '28': ['00', '01', '02', '20', '30', '31', '32', '33', '36', '3C'], + '30': ['00', '01', '02', '20', '30', '31', '32', '33', '36', '38'], + '31': ['00', '01', '02', '20', '30', '31', '32', '33', '36', '38'], + '32': ['00', '01', '02', '20', '30', '31', '32', '33', '36', '38'], + '33': ['00', '01', '02', '20', '30', '31', '32', '33', '36', '38'], + '34': ['00', '01', '02', '20', '30', '31', '32', '33', '36', '3C'], + '35': ['00', '01', '02', '20', '30', '31', '32', '33', '36'], + '40': ['00', '01', '02', '04', '07', '10', '20', '21', '22', '25', '28', '30', '31', '32', '33', '36', '3A', '3B', '3C'], + '41': ['00', '01', '02', '04', '10', '20', '30', '31', '32', '33', '36', '3A', '3C'], + '42': ['00', '01', '02', '04', '10', '20', '30', '31', '32', '33', '36', '3A', '3C'], + '43': ['00', '01', '02', '04', '10', '20', '21', '22', '30', '31', '32', '33', '36', '3A', '3C'], + '44': ['00', '01', '02', '04', '10', '20', '30', '31', '32', '33', '36'], + '45': ['00', '01', '04', '10', '20', '30', '31', '32', '33', '36', '3A', '3B', '3C'], + '46': ['00', '01', '04', '10', '20', '30', '31', '32', '33', '36', '3A', '3B', '3C'], + '47': ['00', '01', '02', '07', '20', '30', '31', '32', '33', '36', '3A'], + '50': ['00', '01', '20', '30', '31', '32', '33', '36', '3C'], + '51': ['00', '01', '20', '30', '31', '32', '33', '36', '3C'], + '60': ['00', '01', '02', '27', '30', '31', '32', '33', '36', '3D'], + '61': ['00', '01', '02', '27', '30', '31', '32', '33', '36', '3D'], + '62': ['00', '01', '02', '10', '27', '30', '31', '32', '33', '36', '3D'], + '70': ['00', '01', '20', '30', '31', '32', '33', '36'], + '71': ['00', '01', '20', '30', '31', '32', '33'], + '72': ['00', '01', '20', '30', '31', '32', '33', '36'], + '73': ['00', '01', '20', '30', '31', '32', '33', '36'], + '79': ['00', '01', '20', '30', '31', '32', '36'], +}; + // The script authoring aliases (the script may also use the hex value). // `no_response` is kept for backward compatibility (12) but is not offered // by the editor - 12's canonical alias is `timeout`. @@ -8036,12 +8088,40 @@ const TR_RESULT_ALIASES = { modified: '07', cancel: '10', back: '11', timeout: '12', no_response: '12', }; +// The command type code of a command name (the editor's select values are the +// names; CMD_NAMES maps the codes) - the first code wins, matching +// testCommandOptions' de-duplication. +function trCommandCode(name) { + const want = String(name === undefined || name === null ? '' : name).toUpperCase(); + for (const k in CMD_NAMES) { + if (CMD_NAMES[k] === want) return parseInt(k, 16); + } + return NaN; +} + // The result select's options: 'hex - alias' where an alias exists, else -// 'hex - spec name', plus a manual hex entry. -function trResultOptions() { - const opts = TR_RESULTS.map(r => ({v: r.alias || r.v, l: r.v + ' - ' + (r.alias || r.name)})); - opts.push({v: 'manual', l: t('manual input')}); - return opts; +// 'hex - spec name', plus a manual hex entry. With opts.command (a command +// name other than ANY) the list is GROUPED by TS 102 223 Tables 6.1/6.2: the +// command-relevant values first, the rest after - every value stays (the +// grouping is ordering-only). +function trResultOptions(opts) { + const label = r => ({v: r.alias || r.v, l: r.v + ' - ' + (r.alias || r.name)}); + const code = opts && opts.command ? trCommandCode(opts.command) : NaN; + const key = Number.isInteger(code) ? code.toString(16).toUpperCase().padStart(2, '0') : ''; + const relevant = key && TR_RESULT_BY_COMMAND[key]; + let out; + if (relevant && relevant.length) { + const rel = TR_RESULTS.filter(r => relevant.indexOf(r.v) >= 0); + const rest = TR_RESULTS.filter(r => relevant.indexOf(r.v) < 0); + out = [{group: t('relevant for') + ' ' + opts.command}] + .concat(rel.map(label)) + .concat([{group: t('all other results')}]) + .concat(rest.map(label)); + } else { + out = TR_RESULTS.map(label); + } + out.push({v: 'manual', l: t('manual input')}); + return out; } // A stored result -> the select's value and the manual hex ('' unless the @@ -8091,7 +8171,7 @@ function testTrResultChanged(sel, wrapId) { function trResultRowHtml(selId, stored, addInfo, opts) { const v = trResultFormValue(stored); const wrapId = selId + '-hexwrap'; - const options = (opts && opts.empty ? [{v: '', l: t(opts.empty)}] : []).concat(trResultOptions()); + const options = (opts && opts.empty ? [{v: '', l: t(opts.empty)}] : []).concat(trResultOptions(opts)); let html = '
' + testFormSelect(selId, v.value, options, "testTrResultChanged(this, '" + wrapId + "')") + '
' @@ -8121,9 +8201,19 @@ function testFormInput(id, value, placeholder, extra) { function testFormSelect(id, value, options, onchange) { let html = ''; } @@ -8274,7 +8364,7 @@ function testStepRender() { const r = step.respond || {}; html += testFormRow('TERMINAL RESPONSE result', trResultRowHtml('test-f-result', r.result === undefined ? 'ok' : r.result, r.additional_info, - {list: true})); + {list: true, command: step.command || 'ANY'})); html += testFormRow('Item identifier (SELECT ITEM / SET UP MENU)', testFormInput('test-f-ritem', r.item_id, '1..255')); html += testFormRow('Text (GET INKEY / GET INPUT)', '
' + testFormInput('test-f-rtext', r.text, 'text') @@ -23065,6 +23155,8 @@ const LANG_RU = { 'Text': 'Текст', 'id': 'id', 'text': 'текст', + 'relevant for': 'подходит для', + 'all other results': 'остальные результаты', 'TERMINAL PROFILE re-sent \u2014 new CAT session': 'TERMINAL PROFILE отправлен заново \u2014 новая CAT-сессия', 'manual input': 'ручной ввод', 'Additional information (optional hex byte)': 'Дополнительная информация (необязательный hex-байт)', diff --git a/frontend/sw.js b/frontend/sw.js index 65cf044..ae06b73 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simple-v420'; +const CACHE = 'simple-v421'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/testscripts.test.js b/frontend/tests/testscripts.test.js index 1ab1aad..440fe36 100644 --- a/frontend/tests/testscripts.test.js +++ b/frontend/tests/testscripts.test.js @@ -62,8 +62,10 @@ eval(extractFunc(html, 'testFormInput')); eval(extractFunc(html, 'testFormSelect')); // the TERMINAL RESPONSE result tables + the shared result-row helpers eval(extractBlock('const TR_RESULTS = [', 'const TR_RESULT_ADD_INFO = [').replace(/^const /gm, 'var ')); -eval(extractBlock('const TR_RESULT_ADD_INFO = [', 'const TR_RESULT_ALIASES = {').replace(/^const /gm, 'var ')); -eval(extractBlock('const TR_RESULT_ALIASES = {', 'function trResultOptions').replace(/^const /gm, 'var ')); +eval(extractBlock('const TR_RESULT_ADD_INFO = [', '// TS 102 223 v18.3.0 Tables 6.1/6.2').replace(/^const /gm, 'var ')); +eval(extractBlock('const TR_RESULT_BY_COMMAND = {', 'const TR_RESULT_ALIASES = {').replace(/^const /gm, 'var ')); +eval(extractBlock('const TR_RESULT_ALIASES = {', 'function trCommandCode').replace(/^const /gm, 'var ')); +eval(extractFunc(html, 'trCommandCode')); eval(extractFunc(html, 'trResultOptions')); eval(extractFunc(html, 'trResultFormValue')); eval(extractFunc(html, 'trResultValid')); diff --git a/frontend/tests/tr_result_by_command.json b/frontend/tests/tr_result_by_command.json new file mode 100644 index 0000000..c0d2d04 --- /dev/null +++ b/frontend/tests/tr_result_by_command.json @@ -0,0 +1,46 @@ +{ + "_note": "TS 102 223 v18.3.0 Tables 6.1/6.2/6.3 \"Proactive commands versus possible terminal response\", parsed from the pinned PDF (docs/uicc/, workspace copy) - which result values the spec lists for each proactive command. The PWA's TR_RESULT_BY_COMMAND mirrors this file (frontend/tests/tr_results.test.js asserts it); the list is used for GROUPING only (the command-relevant values first, the rest after - nothing is hidden). Regenerate with a pdftotext -layout parse of the table pages if the spec pin changes.", + "commands": { + "01": ["00", "01", "02", "03", "04", "08", "20", "30", "31", "32", "33", "36", "3C"], + "02": ["00", "01", "02", "20", "30", "31", "32", "33", "36"], + "03": ["00", "01", "02", "20", "30", "31", "32", "33", "36"], + "04": ["00", "01", "02", "20", "30", "31", "32", "33", "36"], + "05": ["00", "01", "02", "20", "30", "31", "32", "33", "36"], + "10": ["00", "01", "02", "04", "05", "10", "14", "20", "21", "22", "23", "25", "30", "31", "32", "33", "34", "36", "39", "3C"], + "14": ["00", "01", "02", "04", "10", "20", "30", "31", "32", "33", "36", "3C"], + "15": ["00", "01", "02", "20", "21", "26", "30", "31", "32", "33", "3C"], + "20": ["00", "01", "02", "04", "09", "10", "20", "30", "31", "32", "33", "36", "3C"], + "21": ["00", "01", "02", "04", "10", "11", "12", "20", "30", "31", "32", "33", "36", "3C"], + "22": ["00", "01", "02", "04", "10", "11", "12", "13", "20", "30", "31", "32", "33", "36", "3C"], + "23": ["00", "01", "02", "04", "10", "11", "12", "13", "20", "30", "31", "32", "33", "36", "3C"], + "24": ["00", "01", "02", "04", "10", "11", "12", "13", "20", "30", "31", "32", "33", "36", "3C"], + "25": ["00", "01", "02", "04", "20", "30", "31", "32", "33", "36"], + "26": ["00", "01", "02", "06", "20", "30", "31", "32", "33", "36"], + "27": ["00", "01", "02", "20", "24", "30", "31", "32", "33", "36"], + "28": ["00", "01", "02", "20", "30", "31", "32", "33", "36", "3C"], + "30": ["00", "01", "02", "20", "30", "31", "32", "33", "36", "38"], + "31": ["00", "01", "02", "20", "30", "31", "32", "33", "36", "38"], + "32": ["00", "01", "02", "20", "30", "31", "32", "33", "36", "38"], + "33": ["00", "01", "02", "20", "30", "31", "32", "33", "36", "38"], + "34": ["00", "01", "02", "20", "30", "31", "32", "33", "36", "3C"], + "35": ["00", "01", "02", "20", "30", "31", "32", "33", "36"], + "40": ["00", "01", "02", "04", "07", "10", "20", "21", "22", "25", "28", "30", "31", "32", "33", "36", "3A", "3B", "3C"], + "41": ["00", "01", "02", "04", "10", "20", "30", "31", "32", "33", "36", "3A", "3C"], + "42": ["00", "01", "02", "04", "10", "20", "30", "31", "32", "33", "36", "3A", "3C"], + "43": ["00", "01", "02", "04", "10", "20", "21", "22", "30", "31", "32", "33", "36", "3A", "3C"], + "44": ["00", "01", "02", "04", "10", "20", "30", "31", "32", "33", "36"], + "45": ["00", "01", "04", "10", "20", "30", "31", "32", "33", "36", "3A", "3B", "3C"], + "46": ["00", "01", "04", "10", "20", "30", "31", "32", "33", "36", "3A", "3B", "3C"], + "47": ["00", "01", "02", "07", "20", "30", "31", "32", "33", "36", "3A"], + "50": ["00", "01", "20", "30", "31", "32", "33", "36", "3C"], + "51": ["00", "01", "20", "30", "31", "32", "33", "36", "3C"], + "60": ["00", "01", "02", "27", "30", "31", "32", "33", "36", "3D"], + "61": ["00", "01", "02", "27", "30", "31", "32", "33", "36", "3D"], + "62": ["00", "01", "02", "10", "27", "30", "31", "32", "33", "36", "3D"], + "70": ["00", "01", "20", "30", "31", "32", "33", "36"], + "71": ["00", "01", "20", "30", "31", "32", "33"], + "72": ["00", "01", "20", "30", "31", "32", "33", "36"], + "73": ["00", "01", "20", "30", "31", "32", "33", "36"], + "79": ["00", "01", "20", "30", "31", "32", "36"] + } +} diff --git a/frontend/tests/tr_results.test.js b/frontend/tests/tr_results.test.js index 5768b15..b90cc0b 100644 --- a/frontend/tests/tr_results.test.js +++ b/frontend/tests/tr_results.test.js @@ -31,9 +31,12 @@ function extractFunc(src, name) { // Rewrite top-level const -> var so the tables leak out of sloppy-mode eval. eval(extractBlock('const TR_RESULTS = [', 'const TR_RESULT_ADD_INFO = [').replace(/^const /gm, 'var ')); -eval(extractBlock('const TR_RESULT_ADD_INFO = [', 'const TR_RESULT_ALIASES = {').replace(/^const /gm, 'var ')); -eval(extractBlock('const TR_RESULT_ALIASES = {', 'function trResultOptions').replace(/^const /gm, 'var ')); +eval(extractBlock('const TR_RESULT_ADD_INFO = [', '// TS 102 223 v18.3.0 Tables 6.1/6.2').replace(/^const /gm, 'var ')); +eval(extractBlock('const TR_RESULT_BY_COMMAND = {', 'const TR_RESULT_ALIASES = {').replace(/^const /gm, 'var ')); +eval(extractBlock('const TR_RESULT_ALIASES = {', 'function trCommandCode').replace(/^const /gm, 'var ')); +eval(extractBlock('const CMD_NAMES = {', 'function cmdQualifierShort').replace(/^const /gm, 'var ')); eval(extractFunc(html, 'esc')); +eval(extractFunc(html, 'trCommandCode')); eval(extractFunc(html, 'trResultOptions')); eval(extractFunc(html, 'trResultFormValue')); eval(extractFunc(html, 'trResultValid')); @@ -110,7 +113,7 @@ test('the step editor offers the full list for all three result fields', () => { assert.ok(form.includes("{empty: 'same as above'}"), 'the first keeps its empty option'); // the suggestion list is rendered by the first result row of each form // (the drain's respond and the expectation), never twice in one form - assert.strictEqual((form.match(/\{list: true\}/g) || []).length, 2, form); + assert.strictEqual((form.match(/\{list: true/g) || []).length, 2, form); }); test('trResultRowHtml renders the manual entry and the additional info', () => { @@ -135,3 +138,59 @@ test('trResultRowHtml renders the manual entry and the additional info', () => { + trResultRowHtml('test-f-pfirst', '', '', { empty: 'same as above' }); assert.strictEqual((twoRows.match(/id="tr-addinfo-list"/g) || []).length, 1, twoRows); }); + +test('the command/result grouping table matches the parsed spec fixture', () => { + const fixture = JSON.parse(fs.readFileSync(path.join(__dirname, 'tr_result_by_command.json'), 'utf8')); + assert.deepStrictEqual(TR_RESULT_BY_COMMAND, fixture.commands); + // the editor's command names resolve to their type codes (the first code + // wins, matching testCommandOptions' de-duplication) + assert.strictEqual(trCommandCode('REFRESH'), 0x01); + assert.strictEqual(trCommandCode('PLAY TONE'), 0x20); + assert.strictEqual(trCommandCode('TIMER MANAGEMENT'), 0x27); + assert.strictEqual(trCommandCode('OPEN CHANNEL'), 0x40); + assert.ok(Number.isNaN(trCommandCode('ANY'))); + assert.ok(Number.isNaN(trCommandCode('NONSENSE'))); + // every mapped code is a known proactive command + for (const code of Object.keys(TR_RESULT_BY_COMMAND)) { + assert.ok(CMD_NAMES[code], 'the mapped code 0x' + code + ' must be a known command'); + } +}); + +test('trResultOptions groups the list by the selected command', () => { + const flat = trResultOptions(); + assert.strictEqual(flat.filter(o => o.group).length, 0, 'no groups without a command'); + assert.strictEqual(flat.length, TR_RESULTS.length + 1); + assert.strictEqual(trResultOptions({ command: 'ANY' }).filter(o => o.group).length, 0, + 'ANY stays flat'); + const grouped = trResultOptions({ command: 'REFRESH' }); + assert.deepStrictEqual(grouped.filter(o => o.group).map(o => o.group), + ['relevant for REFRESH', 'all other results']); + // the first group carries the spec's REFRESH set in the spec order + const split = grouped.findIndex(o => o.group === 'all other results'); + const first = grouped.slice(1, split); + assert.deepStrictEqual(first.map(o => o.v), + TR_RESULT_BY_COMMAND['01'].map(hex => (TR_RESULTS.find(r => r.v === hex) || {}).alias || hex)); + // nothing is hidden: both groups together are the full list + the manual + // entry, and the stored value always matches an option + const values = grouped.filter(o => !o.group).map(o => o.v).sort(); + const all = TR_RESULTS.map(r => r.alias || r.v).concat(['manual']).sort(); + assert.deepStrictEqual(values, all); +}); + +test('testFormSelect renders the optgroups', () => { + const out = testFormSelect('x', 'ok', [{ group: 'relevant for REFRESH' }, { v: 'ok', l: '00 - ok' }, + { group: 'all other results' }, { v: '1F', l: '1F - Slices status change' }]); + assert.ok(out.includes(''), out); + assert.ok(out.includes(''), out); + assert.strictEqual((out.match(//g) || []).length, 2, out); + assert.ok(out.includes(''), out); + // the flat form is unchanged + assert.ok(!testFormSelect('y', 'ok', [{ v: 'ok', l: '00 - ok' }]).includes('optgroup')); +}); + +test('the expectation result row passes the selected command', () => { + const form = extractFunc(html, 'testStepRender'); + assert.ok(/trResultRowHtml\('test-f-result'[\s\S]*?command: step\.command \|\| 'ANY'/.test(form), + 'the expectation result must group by the selected command'); +}); diff --git a/pyproject.toml b/pyproject.toml index 495d698..1a2715e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pysim-simple-server" -version = "3.23.7" +version = "3.23.8" description = "HTTP REST server wrapping pysim for the SIMple PWA" requires-python = ">=3.8" # pysim is a git-only dependency installed explicitly by setup.bat/setup.sh. diff --git a/pysim_simple_server/server.py b/pysim_simple_server/server.py index 6daa482..64a1b28 100644 --- a/pysim_simple_server/server.py +++ b/pysim_simple_server/server.py @@ -36,7 +36,7 @@ from osmocom.tlv import BER_TLV_IE from osmocom.utils import rpad -VERSION = '3.23.7' +VERSION = '3.23.8' MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE