forked from nohuhu/echi-decode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathechi-decode.pl
executable file
·357 lines (298 loc) · 16.1 KB
/
echi-decode.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#!/usr/bin/perl
# ECHI decoder script (c) 2008-2013 Alex Tokarev <[email protected]>
#
# Usage: echi-decode.pl <binary input file> <csv output file>
#
# Version log:
#
# 1.72: Added an option to specify string delimiter character
# Fixed a bug with date format command line option handling
# 1.71: Fixed a bug with R17 header version
# 1.7: Log is now written to STDERR instead of STDOUT, to accommodate
# for optional data output to STDOUT. Added command line options.
# Updated to CMS R17 data structures (not tested yet).
# Kudos to Alexey Safonov for R17 patch.
# 1.6: Updated to accommodate for CMS 16.3 changes.
# 1.5: Updated for CMS R16. Hopefully in full.
# 1.4: Fixed incorrect field length definition for R11 and R3V8 ECHI formats
# 1.3: Fixed bug with double timezone conversion
# 1.2: Added an experimental fix for CMS DURATION/SEGSTART fields bug
# 1.1: Completely rewrote parsing code, optimized it for speed and size
# 1.0: Initial release
#
#
# Configurable parameters. Should only be set once under normal
# circumstances.
#
#
# Be verbose, print a line for every call record. Use -v and -q
# command line options to override.
#
my $VERBOSE = 1;
#
# Print header line with field names? 1 means Yes, 0 means No.
# If you don't want header line you may just comment this variable out.
# Use -p and -n command line options to override.
#
my $PRINT_HEADER = 1;
#
# Date format for SEGSTART and SEGSTOP fields, in strftime format.
# To have date/time output in UNIX format, set this to an empty string.
# For conventional U.S. format use %c, man strftime for more information.
# For this field to be enclosed in double quotes put them in the format
# string.
# Use -f command line option to override.
#
#my $DATE_FORMAT => '"%c"';
my $DATE_FORMAT = '"%d.%m.%Y %H:%M:%S"';
#
# String field delimiter character, by default a double quote (").
# In CSV file format, it is commonly expected to have string fields
# enclosed in a delimiter characters, like "foo", as opposed to numeric
# fields that usually are not enclosed, like 0.
# Note that this setting *does not* affect date fields - see $DATE_FORMAT
# above.
# In some cases it may be desirable not to enclose string fields, too;
# set this to an empty string '' to achieve that effect.
# Use -s command line option to override.
#
my $STRING_DELIMITER = '"';
############################################################################
#
# PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE!
# Unless you know what you're doing, that is.
#
############################################################################
use strict;
use warnings;
use Getopt::Std qw/ getopts /;
use POSIX qw/ strftime /;
sub logit {
print STDERR join ' ', (scalar localtime), @_;
}
sub dieit {
logit @_;
exit 1;
}
#
# Data record formats. There are all documented ECHI format versions
# so there's no need to mess with them.
#
my %ECHI = eval do { local $/; <DATA> }
or die "Can't eval DATA: $@\n";
$\ = "\n";
{
my %opt;
getopts 'vqpnhf:s:', \%opt;
# Be quiet if -q, verbose if -v, or fall back to config
$VERBOSE = $opt{q} ? 0 : $opt{v} ? 1 : $VERBOSE;
# Don't print header if -n, print if -p, or fall back
$PRINT_HEADER = $opt{n} ? 0 : $opt{p} ? 1 : $PRINT_HEADER;
# Command line trumps configured date format
$DATE_FORMAT = $opt{f} if defined $opt{f};
# String delimiter can be overridden, too
$STRING_DELIMITER = $opt{s} if defined $opt{s};
}
if ($#ARGV < 1) {
die <<"END";
Usage: $0 [parameters] <input chr file> <csv file>
Parameters:
-v -- be verbose, print diagnostic line per every chr record
-q -- be quiet even despite \$VERBOSE variable or -v parameter set
-p -- print CSV header line, listing all column names
-n -- don't print header, takes precedence over variable or -p
-f <format> -- set date format, enclose in '' if there are spaces
-s <char> -- set string delimiter character, default is qouble quote (")
Input and output file names can be dashes (-), in which case STDIN
and STDOUT are used, respectively.
END
};
logit "$0 started" if $VERBOSE;
my ($input_file, $output_file) = @ARGV;
# Two-argument form is used to handle STDIN/STDOUT
open my $input, "<$input_file" or
dieit "Can't open input file $input_file for reading: $!";
open my $output, ">$output_file" or
dieit "Can't open output file $output_file for writing: $!";
binmode $input;
my ($ver, $seq) = do {
read($input, my $buf, 8);
unpack("V2", $buf);
};
die "Unsupported file version $ver, can't process\n"
unless exists $ECHI{$ver};
logit "Processing file $ARGV[0], version $ver, sequence $seq" if $VERBOSE;
# Readability trumps brevity any time
my $processed = 0;
my $echi_format = $ECHI{$ver};
my $header = $echi_format->{header};
my $chunk_length = $echi_format->{length};
my $unpack_format = $echi_format->{format};
my $bits_index = $echi_format->{bits}->{index};
my $bits_format = $echi_format->{bits}->{format};
my $signed = $echi_format->{signed};
my $strstart = $echi_format->{strstart};
my $strstop = $echi_format->{strstop};
my $segment = $echi_format->{segment};
print $output $header if $PRINT_HEADER;
while( read $input, my $buf, $chunk_length ) {
my @data = unpack $unpack_format, $buf;
my $bits = unpack $bits_format, $buf;
splice @data, $bits_index, 0, split //, $bits;
#
# Fix for a weird DURATION/SEGSTART problem
#
if ($data[5] > 0x7fffffff) {
$data[5] = -unpack 'l', pack 'L', $data[5];
# Crude hack but will have to do for now.
# Not sure if there will be any changes to this logic after R16.
$data[6] = $data[($ver >= 16 ? 8 : 7)] - $data[5];
};
if ($DATE_FORMAT) {
for (my $i = 6; $i < ($ver >= 16 ? 10 : 8); $i++) {
$data[$i] = strftime $DATE_FORMAT, gmtime $data[$i];
}
};
foreach my $index (@$signed) {
$data[$index] = unpack 's', pack 'S', $data[$index];
};
for (my $i = $strstart; $i <= ($strstop || $#data); $i++) {
$data[$i] = $STRING_DELIMITER . $data[$i] . $STRING_DELIMITER;
};
dieit "Cannot write to file: $!"
unless print $output join ',', @data;
$processed++;
my $callid = $data[0];
my $segment = $data[$segment];
logit "Processed record $processed, Call ID $callid, Segment $segment"
if $VERBOSE;
};
logit "File $ARGV[0] processed successfully, found $processed records."
if $VERBOSE;
close $input;
close $output;
exit 0;
__DATA__
(
2 => # CMS R3V4 and below
{
length => 189,
header => join ',', qw(
CALLID ACWTIME ANSHOLDTIME
CONSULTTIME DISPTIME DURATION
SEGSTART SEGSTOP TALKTIME
DISPIVECTOR DISPSPLIT FIRSTIVECTOR
SPLIT1 SPLIT2 SPLIT3
TKGRP ASSIST AUDIO
CONFERENCE DA_QUEUED HOLDABN
MALICIOUS OBSERVINGCALL TRANSFERRED
ACD DISPOSITION DISPPRIORITY
HELD SEGMENT EVENT1
EVENT2 EVENT3 EVENT4
EVENT5 EVENT6 EVENT7
EVENT8 EVENT9 DISPVDN
EQLOC FIRSTVDN ORIGLOGIN
ANSLOGIN LASTOBSERVER DIALED_NUM
CALLING_PTY LASTCWC
),
format => 'V9 v7 x1 C14 A6 A10 A6' . 'A10'x3 . 'A25 A13 x17 A17',
bits => { index => 16, format => '@50b8' },
signed => [ 10, 12, 13, 14 ],
segment => 28,
strstart => 37
},
3 => # CMS R3V5
{
length => 210,
header => 'CALLID,ACWTIME,ANSHOLDTIME,CONSULTTIME,DISPTIME,DURATION,SEGSTART,SEGSTOP,TALKTIME,DISPIVECTOR,DISPSPLIT,FIRSTIVECTOR,SPLIT1,SPLIT2,SPLIT3,TKGRP,ASSIST,AUDIO,CONFERENCE,DA_QUEUED,HOLDABN,MALICIOUS,OBSERVINGCALL,TRANSFERRED,AGT_RELEASED,ACD,DISPOSITION,DISPPRIORITY,HELD,SEGMENT,ANSREASON,ORIGREASON,DISPSKLEVEL,EVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8,EVENT9,DISPVDN,EQLOC,FIRSTVDN,ORIGLOGIN,ANSLOGIN,LASTOBSERVER,DIALED_NUM,CALLING_PTY,LASTDIGITS,LASTCWC,CALLING_II',
format => 'V9 v7 x2 C17 A6 A10 A6' . 'A10'x3 . 'A25 A13' . 'A17'x3,
bits => {index => 16, format => '@50b9'},
signed => [10, 12, 13, 14],
segment => 29,
strstart => 41
},
4 => # CMS R3V6
{
length => 225,
header => 'CALLID,ACWTIME,ANSHOLDTIME,CONSULTTIME,DISPTIME,DURATION,SEGSTART,SEGSTOP,TALKTIME,NETINTIME,ORIGHOLDTIME,DISPIVECTOR,DISPSPLIT,FIRSTIVECTOR,SPLIT1,SPLIT2,SPLIT3,TKGRP,ASSIST,AUDIO,CONFERENCE,DA_QUEUED,HOLDABN,MALICIOUS,OBSERVINGCALL,TRANSFERRED,AGT_RELEASED,ACD,DISPOSITION,DISPPRIORITY,HELD,SEGMENT,ANSREASON,ORIGREASON,DISPSKLEVEL,EVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8,EVENT9,UCID,DISPVDN,EQLOC,FIRSTVDN,ORIGLOGIN,ANSLOGIN,LASTOBSERVER,DIALED_NUM,CALLING_PTY,LASTDIGITS,LASTCWC,CALLING_II',
format => 'V11 v7 x2 C17 A21 A6 A10 A6' . 'A10'x3 . 'A25 A13' . 'A17'x2 . 'A3',
bits => {index => 18, format => '@58b9'},
signed => [12, 14, 15, 16],
segment => 31,
strstart => 43
},
5 => # CMS R3V8
{
length => 233,
header => 'CALLID,ACWTIME,ANSHOLDTIME,CONSULTTIME,DISPTIME,DURATION,SEGSTART,SEGSTOP,TALKTIME,NETINTIME,ORIGHOLDTIME,DISPIVECTOR,DISPSPLIT,FIRSTIVECTOR,SPLIT1,SPLIT2,SPLIT3,TKGRP,EQ_LOCID,ORIG_LOCID,ANS_LOCID,OBS_LOCID,ASSIST,AUDIO,CONFERENCE,DA_QUEUED,HOLDABN,MALICIOUS,OBSERVINGCALL,TRANSFERRED,AGT_RELEASED,ACD,DISPOSITION,DISPPRIORITY,HELD,SEGMENT,ANSREASON,ORIGREASON,DISPSKLEVEL,EVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8,EVENT9,UCID,DISPVDN,EQLOC,FIRSTVDN,ORIGLOGIN,ANSLOGIN,LASTOBSERVER,DIALED_NUM,CALLING_PTY,LASTDIGITS,LASTCWC,CALLING_II',
format => 'V11 v11 x2 C17 A21 A6 A10 A6' . 'A10'x3 . 'A25 A13' . 'A17'x2 . 'A3',
bits => {index => 22, format => '@66b9'},
signed => [12, 14, 15, 16],
segment => 35,
strstart => 48
},
11 => # CMS R11
{
length => 322,
header => 'CALLID,ACWTIME,ANSHOLDTIME,CONSULTTIME,DISPTIME,DURATION,SEGSTART,SEGSTOP,TALKTIME,NETINTIME,ORIGHOLDTIME,DISPIVECTOR,DISPSPLIT,FIRSTIVECTOR,SPLIT1,SPLIT2,SPLIT3,TKGRP,EQ_LOCID,ORIG_LOCID,ANS_LOCID,OBS_LOCID,ASSIST,AUDIO,CONFERENCE,DA_QUEUED,HOLDABN,MALICIOUS,OBSERVINGCALL,TRANSFERRED,AGT_RELEASED,ACD,DISPOSITION,DISPPRIORITY,HELD,SEGMENT,ANSREASON,ORIGREASON,DISPSKLEVEL,EVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8,EVENT9,UCID,DISPVDN,EQLOC,FIRSTVDN,ORIGLOGIN,ANSLOGIN,LASTOBSERVER,DIALED_NUM,CALLING_PTY,LASTDIGITS,LASTCWC,CALLING_II,CWC1,CWC2,CWC3,CWC4,CWC5',
format => 'V11 v11 x2 C17 A21 A8 A10 A8' . 'A10'x3 . 'A25 A13' . 'A17'x2 . 'A3' . 'A17'x5,
bits => {index => 22, format => '@66b9'},
signed => [12, 14, 15, 16],
segment => 35,
strstart => 48
},
12 => # CMS R12 to R15
{
length => 493,
header => 'CALLID,ACWTIME,ANSHOLDTIME,CONSULTTIME,DISPTIME,DURATION,SEGSTART,SEGSTOP,TALKTIME,NETINTIME,ORIGHOLDTIME,QUEUETIME,RINGTIME,DISPIVECTOR,DISPSPLIT,FIRSTVECTOR,SPLIT1,SPLIT2,SPLIT3,TKGRP,EQ_LOCID,ORIG_LOCID,ANS_LOCID,OBS_LOCID,UUI_LEN,ASSIST,AUDIO,CONFERENCE,DA_QUEUED,HOLDABN,MALICIOUS,OBSERVINGCALL,TRANSFERRED,AGT_RELEASED,ACD,DISPOSITION,DISPPRIORITY,HELD,SEGMENT,ANSREASON,ORIGREASON,DISPSKLEVEL,EVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8,EVENT9,UCID,DISPVDN,EQLOC,FIRSTVDN,ORIGLOGIN,ANSLOGIN,LASTOBSERVER,DIALED_NUM,CALLING_PTY,LASTDIGITS,LASTCWC,CALLING_II,CWC1,CWC2,CWC3,CWC4,CWC5,VDN2,VDN3,VDN4,VDN5,VDN6,VDN7,VDN8,VDN9,ASAI_UUI',
format => 'V13 v12 x2 C17 A21 A8 A10 A8' . 'A10'x3 . 'A25 A13 A17 A17 A3' . 'A17'x5 . 'A8'x8 . 'A96',
bits => {index => 25, format => '@76b9'},
signed => [14, 16, 17, 18],
segment => 38,
strstart => 51
},
16 => # CMS R16 and above
{
length => 615,
header => 'CALLID,ACWTIME,ANSHOLDTIME,CONSULTTIME,DISPTIME,DURATION,SEGSTART,SEGSTART_UTC,SEGSTOP,SEGSTOP_UTC,TALKTIME,NETINTIME,ORIGHOLDTIME,QUEUETIME,RINGTIME,DISPIVECTOR,DISPSPLIT,FIRSTIVECTOR,SPLIT1,SPLIT2,SPLIT3,TKGRP,EQ_LOCID,ORIG_LOCID,ANS_LOCID,OBS_LOCID,UUI_LEN,ASSIST,AUDIO,CONFERENCE,DA_QUEUED,HOLDABN,MALICIOUS,OBSERVINGCALL,TRANSFERRED,AGT_RELEASED,ACD,CALL_DISP,DISPPRIORITY,HELD,SEGMENT,ANSREASON,ORIGREASON,DISPSKLEVEL,EVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8,EVENT9,UCID,DISPVDN,EQLOC,FIRSTVDN,ORIGLOGIN,ANSLOGIN,LASTOBSERVER,DIALED_NUM,CALLING_PTY,LASTDIGITS,LASTCWC,CALLING_II,CWC1,CWC2,CWC3,CWC4,CWC5,VDN2,VDN3,VDN4,VDN5,VDN6,VDN7,VDN8,VDN9,ASAI_UUI,INTERRUPTDEL,AGENTSURPLUS,AGENTSKILLLEVEL,PREFSKILLLEVEL',
format => 'V15 v12 x2 C17 A21 A16 A10' . 'A16 'x4 . 'A25 A25 A17 A17 A3' . 'A17 'x5 . 'A16 'x8 . 'A96 C4',
bits => {index => 27, format => '@76b9'},
signed => [16, 18, 19, 20],
segment => 40,
strstart => 53,
strstop => 78
},
163 => # CMS R16.3 and above
{
length => 617,
header => 'CALLID,ACWTIME,ANSHOLDTIME,CONSULTTIME,DISPTIME,DURATION,SEGSTART,SEGSTART_UTC,SEGSTOP,SEGSTOP_UTC,TALKTIME,NETINTIME,ORIGHOLDTIME,QUEUETIME,RINGTIME,DISPIVECTOR,DISPSPLIT,FIRSTIVECTOR,SPLIT1,SPLIT2,SPLIT3,TKGRP,EQ_LOCID,ORIG_LOCID,ANS_LOCID,OBS_LOCID,UUI_LEN,ASSIST,AUDIO,CONFERENCE,DA_QUEUED,HOLDABN,MALICIOUS,OBSERVINGCALL,TRANSFERRED,AGT_RELEASED,ACD,CALL_DISP,DISPPRIORITY,HELD,SEGMENT,ANSREASON,ORIGREASON,DISPSKLEVEL,EVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8,EVENT9,UCID,DISPVDN,EQLOC,FIRSTVDN,ORIGLOGIN,ANSLOGIN,LASTOBSERVER,DIALED_NUM,CALLING_PTY,LASTDIGITS,LASTCWC,CALLING_II,CWC1,CWC2,CWC3,CWC4,CWC5,VDN2,VDN3,VDN4,VDN5,VDN6,VDN7,VDN8,VDN9,ASAI_UUI,INTERRUPTDEL,AGENTSURPLUS,AGENTSKILLLEVEL,PREFSKILLLEVEL,ICRRESENT,ICRPULLREASON',
format => 'V15 v12 x2 C17 A21 A16 A10' . 'A16 'x4 . 'A25 A25 A17 A17 A3' . 'A17 'x5 . 'A16 'x8 . 'A96 C6',
bits => {index => 27, format => '@76b9'},
signed => [16, 18, 19, 20],
segment => 40,
strstart => 53,
strstop => 78
},
170 => # CMS R17 and above
{
length => 629,
header => 'CALLID,ACWTIME,ANSHOLDTIME,CONSULTTIME,DISPTIME,DURATION,SEGSTART,SEGSTART_UTC,SEGSTOP,SEGSTOP_UTC,TALKTIME,NETINTIME,ORIGHOLDTIME,QUEUETIME,RINGTIME,ORIG_ATTRIB_ID,ANS_ATTRIB_ID,OBS_ATTRIB_ID,DISPIVECTOR,DISPSPLIT,FIRSTIVECTOR,SPLIT1,SPLIT2,SPLIT3,TKGRP,EQ_LOCID,ORIG_LOCID,ANS_LOCID,OBS_LOCID,UUI_LEN,ASSIST,AUDIO,CONFERENCE,DA_QUEUED,HOLDABN,MALICIOUS,OBSERVINGCALL,TRANSFERRED,AGT_RELEASED,ACD,CALL_DISP,DISPPRIORITY,HELD,SEGMENT,ANSREASON,ORIGREASON,DISPSKLEVEL,EVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8,EVENT9,UCID,DISPVDN,EQLOC,FIRSTVDN,ORIGLOGIN,ANSLOGIN,LASTOBSERVER,DIALED_NUM,CALLING_PTY,LASTDIGITS,LASTCWC,CALLING_II,CWC1,CWC2,CWC3,CWC4,CWC5,VDN2,VDN3,VDN4,VDN5,VDN6,VDN7,VDN8,VDN9,ASAI_UUI,INTERRUPTDEL,AGENTSURPLUS,AGENTSKILLLEVEL,PREFSKILLLEVEL,ICRRESENT,ICRPULLREASON',
format => 'V18 v12 x2 C17 A21 A16 A10' . 'A16 'x4 . 'A25 A25 A17 A17 A3' . 'A17 'x5 . 'A16 'x8 . 'A96 C6',
bits => {index => 30, format => '@76b9'},
signed => [19, 21, 22, 23],
segment => 43,
strstart => 56,
strstop => 81
}
180 => # CMS R18
{
length => 697,
header => 'CALLID,ACWTIME,ANSHOLDTIME,CONSULTTIME,DISPTIME,DURATION,SEGSTART,SEGSTART_UTC,SEGSTOP,SEGSTOP_UTC,TALKTIME,NETINTIME,ORIGHOLDTIME,QUEUETIME,RINGTIME,TENANT,DISPIVECTOR,DISPSPLIT,FIRSTIVECTOR,SPLIT1,SPLIT2,SPLIT3,TKGRP,EQ_LOCID,ORIG_LOCID,ANS_LOCID,OBS_LOCID,UUI_LEN,ASSIST,AUDIO,CONFERENCE,DA_QUEUED,HOLDABN,MALICIOUS,OBSERVINGCALL,TRANSFERRED,AGT_RELEASED,ACD,CALL_DISP,DISPPRIORITY,HELD,SEGMENT,ANSREASON,ORIGREASON,DISPSKLEVEL,event1,event2,event3,event4,event5,event6,event7,event8,event9,UCID,DISPVDN,EQLOC,FIRSTVDN,ORIGLOGIN,ANSLOGIN,LASTOBSERVER,DIALED_NUM,CALLING_PTY,LASTDIGITS,LASTCWC,calling_ii,cwc1,cwc2,cwc3,cwc4,cwc5,vdn2,vdn3,vdn4,vdn5,vdn6,vdn7,vdn8,vdn9,ASAI_UUI,INTERRUPTDEL,AGENTSURPLUS,AGENTSKILLLEVEL,PREFSKILLLEVEL,ICRRESENT,ICRPULLREASON,ORIG_ATTRIB_ID,ANS_ATTRIB_ID,OBS_ATTRIB_ID',
format => 'V16 v12 x2 C17 A21 A17 A10' . 'A17'x4 . 'A25 A25 A17 A17 A3' . 'A17'x5 . 'A17'x8 . 'A96 C6' . 'A21'x3,
bits => {index => 28, format => '@88b9'},
signed => [17, 19, 20, 21],
segment => 41,
strstart => 54,
strstop => 88
}
)