diff --git a/libs/spandsp/spandsp-sim/spandsp/line_model.h b/libs/spandsp/spandsp-sim/spandsp/line_model.h index a8131e2707..ce8f7ddd09 100644 --- a/libs/spandsp/spandsp-sim/spandsp/line_model.h +++ b/libs/spandsp/spandsp-sim/spandsp/line_model.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: line_model.h,v 1.7 2009/09/23 16:02:59 steveu Exp $ + * $Id: line_model.h,v 1.7.4.1 2009/12/19 10:16:44 steveu Exp $ */ /*! \file */ @@ -70,7 +70,7 @@ typedef struct codec_munge_state_t *munge; /*! The coefficients for the near end analogue section simulation filter */ - float *near_filter; + const float *near_filter; /*! The number of coefficients for the near end analogue section simulation filter */ int near_filter_len; /*! Last transmitted samples (ring buffer, used by the line filter) */ @@ -88,7 +88,7 @@ typedef struct int16_t bulk_delay_buf[8000]; /*! The coefficients for the far end analogue section simulation filter */ - float *far_filter; + const float *far_filter; /*! The number of coefficients for the far end analogue section simulation filter */ int far_filter_len; /*! Last transmitted samples (ring buffer, used by the line filter) */ diff --git a/libs/spandsp/src/Makefile.am b/libs/spandsp/src/Makefile.am index 6230430e16..3ed16a618b 100644 --- a/libs/spandsp/src/Makefile.am +++ b/libs/spandsp/src/Makefile.am @@ -16,13 +16,37 @@ ## License along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ## -## $Id: Makefile.am,v 1.137 2009/09/22 14:52:31 steveu Exp $ +## $Id: Makefile.am,v 1.138.4.3 2009/12/19 10:30:10 steveu Exp $ AM_CFLAGS = $(COMP_VENDOR_CFLAGS) AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) MAINTAINERCLEANFILES = Makefile.in +DISTCLEANFILES = $(srcdir)/at_interpreter_dictionary.h \ + $(srcdir)/v17_v32bis_rx_fixed_rrc.h \ + $(srcdir)/v17_v32bis_rx_floating_rrc.h \ + $(srcdir)/v17_v32bis_tx_fixed_rrc.h \ + $(srcdir)/v17_v32bis_tx_floating_rrc.h \ + $(srcdir)/v22bis_rx_1200_fixed_rrc.h \ + $(srcdir)/v22bis_rx_2400_fixed_rrc.h \ + $(srcdir)/v22bis_rx_1200_floating_rrc.h \ + $(srcdir)/v22bis_rx_2400_floating_rrc.h \ + $(srcdir)/v22bis_tx_fixed_rrc.h \ + $(srcdir)/v22bis_tx_floating_rrc.h \ + $(srcdir)/v27ter_rx_2400_fixed_rrc.h \ + $(srcdir)/v27ter_rx_4800_fixed_rrc.h \ + $(srcdir)/v27ter_rx_2400_floating_rrc.h \ + $(srcdir)/v27ter_rx_4800_floating_rrc.h \ + $(srcdir)/v27ter_tx_2400_fixed_rrc.h \ + $(srcdir)/v27ter_tx_4800_fixed_rrc.h \ + $(srcdir)/v27ter_tx_2400_floating_rrc.h \ + $(srcdir)/v27ter_tx_4800_floating_rrc.h \ + $(srcdir)/v29rx_fixed_rrc.h \ + $(srcdir)/v29rx_floating_rrc.h \ + $(srcdir)/v29tx_fixed_rrc.h \ + $(srcdir)/v29tx_floating_rrc.h + EXTRA_DIST = floating_fudge.h \ libspandsp.dsp \ libspandsp.2005.sln \ @@ -31,6 +55,9 @@ EXTRA_DIST = floating_fudge.h \ libspandsp.2008.vcproj \ libtiff.2005.vcproj \ libtiff.2008.vcproj \ + filter_tools.c \ + make_at_dictionary.c \ + make_modem_filter.c \ msvc/config.h \ msvc/Download_TIFF.2005.vcproj \ msvc/Download_TIFF.2008.vcproj \ @@ -111,7 +138,8 @@ libspandsp_la_SOURCES = adsi.c \ super_tone_rx.c \ super_tone_tx.c \ swept_tone.c \ - t4.c \ + t4_rx.c \ + t4_tx.c \ t30.c \ t30_api.c \ t30_logging.c \ @@ -190,7 +218,8 @@ nobase_include_HEADERS = spandsp/adsi.h \ spandsp/super_tone_rx.h \ spandsp/super_tone_tx.h \ spandsp/swept_tone.h \ - spandsp/t4.h \ + spandsp/t4_rx.h \ + spandsp/t4_tx.h \ spandsp/t30.h \ spandsp/t30_api.h \ spandsp/t30_fcf.h \ @@ -252,12 +281,14 @@ nobase_include_HEADERS = spandsp/adsi.h \ spandsp/private/super_tone_tx.h \ spandsp/private/swept_tone.h \ spandsp/private/t30.h \ + spandsp/private/t30_dis_dtc_dcs_bits.h \ spandsp/private/t31.h \ spandsp/private/t38_core.h \ spandsp/private/t38_gateway.h \ spandsp/private/t38_non_ecm_buffer.h \ spandsp/private/t38_terminal.h \ - spandsp/private/t4.h \ + spandsp/private/t4_rx.h \ + spandsp/private/t4_tx.h \ spandsp/private/time_scale.h \ spandsp/private/tone_detect.h \ spandsp/private/tone_generate.h \ @@ -282,7 +313,7 @@ noinst_HEADERS = faxfont.h \ lpc10_encdecs.h \ mmx_sse_decs.h \ t30_local.h \ - t4_states.h \ + t4_t6_decode_states.h \ v17_v32bis_rx_constellation_maps.h \ v17_v32bis_tx_constellation_maps.h \ v29tx_constellation_maps.h @@ -290,7 +321,7 @@ noinst_HEADERS = faxfont.h \ make_at_dictionary$(EXEEXT): $(top_srcdir)/src/make_at_dictionary.c $(CC_FOR_BUILD) -o make_at_dictionary$(EXEEXT) $(top_srcdir)/src/make_at_dictionary.c -DHAVE_CONFIG_H -I$(top_builddir)/src -make_modem_filter$(EXEEXT): $(top_srcdir)/src/make_modem_filter.c $(top_srcdir)/src/filter_tools.c +make_modem_filter$(EXEEXT): $(top_srcdir)/src/make_modem_filter.c $(top_srcdir)/src/filter_tools.c $(CC_FOR_BUILD) -o make_modem_filter$(EXEEXT) $(top_srcdir)/src/make_modem_filter.c $(top_srcdir)/src/filter_tools.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm # We need to run make_at_dictionary, so it generates the @@ -489,13 +520,10 @@ $(srcdir)/msvc/spandsp.h: spandsp.h.in -e "s/\@INSERT_MATH_HEADER\@/#include /" $(srcdir)/spandsp.h.in > $(srcdir)/msvc/spandsp.h spandsp/version.h: + mkdir -p $(@D) NOWDATE=`date --utc +"%Y%m%d"` ; \ NOWTIME=`date --utc +"%H%M%S"` ; \ sed 's/$$SPANDSP_RELEASE_DATE/'$$NOWDATE'/;s/$$SPANDSP_RELEASE_TIME/'$$NOWTIME'/' \ - spandsp/version.h + <$(srcdir)/spandsp/version.h.in >$@ -dist-hook: - NOWDATE=`date --utc +"%Y%m%d"` ; \ - NOWTIME=`date --utc +"%H%M%S"` ; \ - sed 's/$$SPANDSP_RELEASE_DATE/'$$NOWDATE'/;s/$$SPANDSP_RELEASE_TIME/'$$NOWTIME'/' \ - spandsp/version.h +dist-hook: spandsp/version.h diff --git a/libs/spandsp/src/adsi.c b/libs/spandsp/src/adsi.c index b6ae4d0bdb..33df514ff9 100644 --- a/libs/spandsp/src/adsi.c +++ b/libs/spandsp/src/adsi.c @@ -23,7 +23,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: adsi.c,v 1.76 2009/04/12 09:12:10 steveu Exp $ + * $Id: adsi.c,v 1.77 2009/11/02 13:25:20 steveu Exp $ */ /*! \file */ @@ -431,12 +431,12 @@ SPAN_DECLARE(adsi_rx_state_t *) adsi_rx_init(adsi_rx_state_t *s, switch (standard) { case ADSI_STANDARD_CLASS: - fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_BELL202], FALSE, adsi_rx_put_bit, s); + fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_BELL202], FSK_FRAME_MODE_ASYNC, adsi_rx_put_bit, s); break; case ADSI_STANDARD_CLIP: case ADSI_STANDARD_ACLIP: case ADSI_STANDARD_JCLIP: - fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_V23CH1], FALSE, adsi_rx_put_bit, s); + fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_V23CH1], FSK_FRAME_MODE_ASYNC, adsi_rx_put_bit, s); break; case ADSI_STANDARD_CLIP_DTMF: dtmf_rx_init(&(s->dtmfrx), adsi_rx_dtmf, s); @@ -444,7 +444,7 @@ SPAN_DECLARE(adsi_rx_state_t *) adsi_rx_init(adsi_rx_state_t *s, case ADSI_STANDARD_TDD: /* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and ride over the fraction. */ - fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], 7, adsi_tdd_put_async_byte, s); + fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], FSK_FRAME_MODE_5N1_FRAMES, adsi_tdd_put_async_byte, s); break; } s->standard = standard; diff --git a/libs/spandsp/src/at_interpreter.c b/libs/spandsp/src/at_interpreter.c index ffd39301ee..07486746da 100644 --- a/libs/spandsp/src/at_interpreter.c +++ b/libs/spandsp/src/at_interpreter.c @@ -25,7 +25,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: at_interpreter.c,v 1.41 2009/10/03 04:37:25 steveu Exp $ + * $Id: at_interpreter.c,v 1.42 2009/10/09 14:53:56 steveu Exp $ */ /*! \file */ @@ -3358,9 +3358,30 @@ static const char *at_cmd_plus_EWIND(at_state_t *s, const char *t) } /*- End of function --------------------------------------------------------*/ +static const char *at_cmd_plus_F34(at_state_t *s, const char *t) +{ + static const int maxes[5] = + { + 14, 14, 2, 14, 14 + }; + int *locations[5]; + int i; + + /* T.31 B.6.1 - Initial V.34 rate controls for FAX */ + /* Syntax: +F34=[][,[][,][,][,logging, SPAN_LOG_FLOW, "FAX tone declared %s (%ddBm0)\n", (on) ? "on" : "off", level); + span_log(&s->logging, SPAN_LOG_FLOW, "%s detected (%ddBm0)\n", modem_connect_tone_to_str(tone), level); } /*- End of function --------------------------------------------------------*/ @@ -423,7 +425,7 @@ static void fax_set_rx_type(void *user_data, int type, int bit_rate, int short_t switch (type) { case T30_MODEM_V21: - fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, put_bit_user_data); + fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, put_bit_user_data); fsk_rx_signal_cutoff(&t->v21_rx, -45.5f); set_rx_handler(s, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &t->v21_rx); break; diff --git a/libs/spandsp/src/fax_modems.c b/libs/spandsp/src/fax_modems.c index 9b409d59cf..bc8404036c 100644 --- a/libs/spandsp/src/fax_modems.c +++ b/libs/spandsp/src/fax_modems.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: fax_modems.c,v 1.7 2009/10/05 16:33:25 steveu Exp $ + * $Id: fax_modems.c,v 1.8 2009/11/02 13:25:20 steveu Exp $ */ /*! \file */ @@ -45,6 +45,9 @@ #include #include #include +#if defined(LOG_FAX_AUDIO) +#include +#endif #include "spandsp/telephony.h" #include "spandsp/logging.h" @@ -280,7 +283,7 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, user_data); hdlc_tx_init(&s->hdlc_tx, FALSE, 2, FALSE, hdlc_tx_underflow, user_data); - fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx); + fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx); fsk_rx_signal_cutoff(&s->v21_rx, -39.09f); fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx); v17_rx_init(&s->v17_rx, 14400, non_ecm_put_bit, user_data); diff --git a/libs/spandsp/src/fsk.c b/libs/spandsp/src/fsk.c index a638ea712f..8e07ada884 100644 --- a/libs/spandsp/src/fsk.c +++ b/libs/spandsp/src/fsk.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: fsk.c,v 1.59 2009/06/02 16:03:56 steveu Exp $ + * $Id: fsk.c,v 1.60 2009/11/02 13:25:20 steveu Exp $ */ /*! \file */ @@ -128,6 +128,22 @@ const fsk_spec_t preset_fsk_specs[] = } }; +SPAN_DECLARE(int) fsk_tx_restart(fsk_tx_state_t *s, const fsk_spec_t *spec) +{ + s->baud_rate = spec->baud_rate; + s->phase_rates[0] = dds_phase_rate((float) spec->freq_zero); + s->phase_rates[1] = dds_phase_rate((float) spec->freq_one); + s->scaling = dds_scaling_dbm0((float) spec->tx_level); + /* Initialise fractional sample baud generation. */ + s->phase_acc = 0; + s->baud_frac = 0; + s->current_phase_rate = s->phase_rates[1]; + + s->shutdown = FALSE; + return 0; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s, const fsk_spec_t *spec, get_bit_func_t get_bit, @@ -138,20 +154,11 @@ SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s, if ((s = (fsk_tx_state_t *) malloc(sizeof(*s))) == NULL) return NULL; } + memset(s, 0, sizeof(*s)); - s->baud_rate = spec->baud_rate; s->get_bit = get_bit; s->get_bit_user_data = user_data; - - s->phase_rates[0] = dds_phase_rate((float) spec->freq_zero); - s->phase_rates[1] = dds_phase_rate((float) spec->freq_one); - s->scaling = dds_scaling_dbm0((float) spec->tx_level); - /* Initialise fractional sample baud generation. */ - s->phase_acc = 0; - s->baud_frac = 0; - s->current_phase_rate = s->phase_rates[1]; - - s->shutdown = FALSE; + fsk_tx_restart(s, spec); return s; } /*- End of function --------------------------------------------------------*/ @@ -250,26 +257,13 @@ SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_tx_s } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s, - const fsk_spec_t *spec, - int framing_mode, - put_bit_func_t put_bit, - void *user_data) +SPAN_DECLARE(int) fsk_rx_restart(fsk_rx_state_t *s, const fsk_spec_t *spec, int framing_mode) { int chop; - if (s == NULL) - { - if ((s = (fsk_rx_state_t *) malloc(sizeof(*s))) == NULL) - return NULL; - } - - memset(s, 0, sizeof(*s)); s->baud_rate = spec->baud_rate; s->framing_mode = framing_mode; fsk_rx_signal_cutoff(s, (float) spec->min_level); - s->put_bit = put_bit; - s->put_bit_user_data = user_data; /* Detect by correlating against the tones we want, over a period of one baud. The correlation must be quadrature. */ @@ -307,6 +301,26 @@ SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s, /* Initialise a power detector, so sense when a signal is present. */ power_meter_init(&(s->power), 4); s->signal_present = 0; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s, + const fsk_spec_t *spec, + int framing_mode, + put_bit_func_t put_bit, + void *user_data) +{ + if (s == NULL) + { + if ((s = (fsk_rx_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + + s->put_bit = put_bit; + s->put_bit_user_data = user_data; + fsk_rx_restart(s, spec, framing_mode); return s; } /*- End of function --------------------------------------------------------*/ @@ -421,7 +435,7 @@ SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len) baudstate = (sum[0] < sum[1]); switch (s->framing_mode) { - case 1: + case FSK_FRAME_MODE_SYNC: /* Synchronous serial operation - e.g. for HDLC */ if (s->last_bit != baudstate) { @@ -442,7 +456,7 @@ SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len) s->put_bit(s->put_bit_user_data, baudstate); } break; - case 0: + case FSK_FRAME_MODE_ASYNC: /* Fully asynchronous mode */ if (s->last_bit != baudstate) { diff --git a/libs/spandsp/src/gsm0610_rpe.c b/libs/spandsp/src/gsm0610_rpe.c index 416dcc311a..4a218c44a8 100644 --- a/libs/spandsp/src/gsm0610_rpe.c +++ b/libs/spandsp/src/gsm0610_rpe.c @@ -25,7 +25,7 @@ * This code is based on the widely used GSM 06.10 code available from * http://kbs.cs.tu-berlin.de/~jutta/toast.html * - * $Id: gsm0610_rpe.c,v 1.25 2009/02/03 16:28:39 steveu Exp $ + * $Id: gsm0610_rpe.c,v 1.25.4.1 2009/12/19 09:47:56 steveu Exp $ */ /*! \file */ @@ -87,13 +87,13 @@ static void weighting_filter(const int16_t *e, // signal [-5..0.39.44] IN " emms;\n" " addl $-10,%%ecx;\n" " movl $0x1000,%%eax;\n" - " movd %%eax,%%mm5;\n" /* for rounding */ + " movd %%eax,%%mm5;\n" /* For rounding */ " movq %[gsm_H],%%mm1;\n" " movq %[gsm_H8],%%mm2;\n" " movq %[gsm_H16],%%mm3;\n" " xorl %%esi,%%esi;\n" " .p2align 2;\n" - "1:;\n" + "1:\n" " movq (%%ecx,%%esi,2),%%mm0;\n" " pmaddwd %%mm1,%%mm0;\n" diff --git a/libs/spandsp/src/libspandsp.2005.vcproj b/libs/spandsp/src/libspandsp.2005.vcproj index 453f519b61..695840c9be 100644 --- a/libs/spandsp/src/libspandsp.2005.vcproj +++ b/libs/spandsp/src/libspandsp.2005.vcproj @@ -143,7 +143,8 @@ - + + @@ -221,7 +222,8 @@ - + + @@ -283,12 +285,14 @@ + - + + diff --git a/libs/spandsp/src/libspandsp.2008.vcproj b/libs/spandsp/src/libspandsp.2008.vcproj index c0bb6f77e9..6f57c7801e 100644 --- a/libs/spandsp/src/libspandsp.2008.vcproj +++ b/libs/spandsp/src/libspandsp.2008.vcproj @@ -213,7 +213,8 @@ - + + @@ -291,7 +292,8 @@ - + + @@ -353,12 +355,14 @@ + - + + diff --git a/libs/spandsp/src/libspandsp.dsp b/libs/spandsp/src/libspandsp.dsp index 96f955ebf4..d300d3a3cf 100644 --- a/libs/spandsp/src/libspandsp.dsp +++ b/libs/spandsp/src/libspandsp.dsp @@ -297,7 +297,11 @@ SOURCE=.\swept_tone.c # End Source File # Begin Source File -SOURCE=.\t4.c +SOURCE=.\t4_rx.c +# End Source File +# Begin Source File + +SOURCE=.\t4_tx.c # End Source File # Begin Source File @@ -607,7 +611,11 @@ SOURCE=.\spandsp/swept_tone.h # End Source File # Begin Source File -SOURCE=.\spandsp/t4.h +SOURCE=.\spandsp/t4_rx.h +# End Source File +# Begin Source File + +SOURCE=.\spandsp/t4_tx.h # End Source File # Begin Source File @@ -855,6 +863,10 @@ SOURCE=.\spandsp/private/t30.h # End Source File # Begin Source File +SOURCE=.\spandsp/private/t30_dis_dtc_dcs_bits.h +# End Source File +# Begin Source File + SOURCE=.\spandsp/private/t31.h # End Source File # Begin Source File @@ -875,7 +887,11 @@ SOURCE=.\spandsp/private/t38_terminal.h # End Source File # Begin Source File -SOURCE=.\spandsp/private/t4.h +SOURCE=.\spandsp/private/t4_rx.h +# End Source File +# Begin Source File + +SOURCE=.\spandsp/private/t4_tx.h # End Source File # Begin Source File diff --git a/libs/spandsp/src/make_at_dictionary.c b/libs/spandsp/src/make_at_dictionary.c index f79a26eb0d..874bd5469c 100644 --- a/libs/spandsp/src/make_at_dictionary.c +++ b/libs/spandsp/src/make_at_dictionary.c @@ -23,7 +23,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: make_at_dictionary.c,v 1.5 2009/10/05 16:36:42 steveu Exp $ + * $Id: make_at_dictionary.c,v 1.6 2009/10/09 14:53:57 steveu Exp $ */ #if defined(HAVE_CONFIG_H) @@ -231,6 +231,7 @@ const char *wordlist[] = "+ESR", /* V.250 6.5.3 - Selective repeat */ "+ETBM", /* V.250 6.5.6 - Call termination buffer management */ "+EWIND", /* V.250 6.5.7 - Window size */ + "+F34", /* T.31 B.6.1 - Initial V.34 rate controls for FAX */ "+FAA", /* T.32 8.5.2.5 - Adaptive Answer parameter */ "+FAP", /* T.32 8.5.1.12 - Addressing and polling capabilities parameter */ "+FAR", /* T.31 8.5.1 - Adaptive reception control */ diff --git a/libs/spandsp/src/modem_connect_tones.c b/libs/spandsp/src/modem_connect_tones.c index 68da1df73a..93e0b31485 100644 --- a/libs/spandsp/src/modem_connect_tones.c +++ b/libs/spandsp/src/modem_connect_tones.c @@ -23,11 +23,23 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: modem_connect_tones.c,v 1.37 2009/06/02 16:03:56 steveu Exp $ + * $Id: modem_connect_tones.c,v 1.41 2009/11/06 19:21:33 steveu Exp $ */ /*! \file */ +/* CNG is 0.5s+-15% of 1100+-38Hz, 3s+-15% off, repeating. + + CED is 0.2s silence, 3.3+-0.7s of 2100+-15Hz, and 75+-20ms of silence. + + ANS is 3.3+-0.7s of 2100+-15Hz. + + ANS/ is 3.3+-0.7s of 2100+-15Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms. + + ANSam/ is 2100+-1Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms, and AM with a sinewave of 15+-0.1Hz. + The modulated envelope ranges in amplitude between (0.8+-0.01) and (1.2+-0.01) times its average + amplitude. It lasts up to 5s, but will be stopped early if the V.8 protocol proceeds. */ + #if defined(HAVE_CONFIG_H) #include "config.h" #endif @@ -158,9 +170,9 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t * case MODEM_CONNECT_TONES_ANSAM: if (s->duration_timer < len) len = s->duration_timer; - if (s->duration_timer > ms_to_samples(3300)) + if (s->duration_timer > ms_to_samples(5000)) { - if ((i = s->duration_timer - ms_to_samples(3300)) > len) + if ((i = s->duration_timer - ms_to_samples(5000)) > len) i = len; memset(amp, 0, sizeof(int16_t)*i); } @@ -174,9 +186,9 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t * case MODEM_CONNECT_TONES_ANSAM_PR: if (s->duration_timer < len) len = s->duration_timer; - if (s->duration_timer > ms_to_samples(3300)) + if (s->duration_timer > ms_to_samples(5000)) { - if ((i = s->duration_timer - ms_to_samples(3300)) > len) + if ((i = s->duration_timer - ms_to_samples(5000)) > len) i = len; memset(amp, 0, sizeof(int16_t)*i); } @@ -221,28 +233,48 @@ SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem s->tone_phase = 0; s->mod_phase = 0; s->mod_level = 0; + s->hop_timer = 0; break; case MODEM_CONNECT_TONES_ANS: case MODEM_CONNECT_TONES_ANSAM: /* 0.2s of silence, then 2.6s to 4s of 2100Hz+-15Hz tone, then 75ms of silence. */ s->tone_phase_rate = dds_phase_rate(2100.0); s->level = dds_scaling_dbm0(-11); - s->duration_timer = ms_to_samples(200 + 2600); - s->mod_phase_rate = dds_phase_rate(15.0); + if (s->tone_type == MODEM_CONNECT_TONES_ANSAM) + { + s->mod_phase_rate = dds_phase_rate(15.0); + s->mod_level = s->level/5; + s->duration_timer = ms_to_samples(200 + 5000); + } + else + { + s->mod_phase_rate = 0; + s->mod_level = 0; + s->duration_timer = ms_to_samples(200 + 2600); + } s->tone_phase = 0; s->mod_phase = 0; - s->mod_level = (s->tone_type == MODEM_CONNECT_TONES_ANSAM) ? s->level/5 : 0; + s->hop_timer = 0; break; case MODEM_CONNECT_TONES_ANS_PR: case MODEM_CONNECT_TONES_ANSAM_PR: s->tone_phase_rate = dds_phase_rate(2100.0); s->level = dds_scaling_dbm0(-12); - s->duration_timer = ms_to_samples(200 + 3300); - s->mod_phase_rate = dds_phase_rate(15.0); + if (s->tone_type == MODEM_CONNECT_TONES_ANSAM_PR) + { + s->mod_phase_rate = dds_phase_rate(15.0); + s->mod_level = s->level/5; + s->duration_timer = ms_to_samples(200 + 5000); + } + else + { + s->mod_phase_rate = 0; + s->mod_level = 0; + s->duration_timer = ms_to_samples(200 + 3300); + } s->tone_phase = 0; s->mod_phase = 0; s->hop_timer = ms_to_samples(450); - s->mod_level = (s->tone_type == MODEM_CONNECT_TONES_ANSAM_PR) ? s->level/5 : 0; break; default: if (alloced) @@ -362,19 +394,20 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * int16_t notched; float v1; float famp; - + float filtered; + switch (s->tone_type) { case MODEM_CONNECT_TONES_FAX_CNG: for (i = 0; i < len; i++) { + famp = amp[i]; /* A Cauer notch at 1100Hz, spread just wide enough to meet our detection bandwidth criteria. */ - famp = amp[i]; - v1 = 0.792928f*famp + 1.0018744927985f*s->z1 - 0.54196833412465f*s->z2; - famp = v1 - 1.2994747954630f*s->z1 + s->z2; - s->z2 = s->z1; - s->z1 = v1; + v1 = 0.792928f*famp + 1.0018744927985f*s->znotch_1 - 0.54196833412465f*s->znotch_2; + famp = v1 - 1.2994747954630f*s->znotch_1 + s->znotch_2; + s->znotch_2 = s->znotch_1; + s->znotch_1 = v1; notched = (int16_t) lfastrintf(famp); /* Estimate the overall energy in the channel, and the energy in @@ -413,22 +446,29 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * case MODEM_CONNECT_TONES_ANS: for (i = 0; i < len; i++) { + famp = amp[i]; + /* A Cauer bandpass at 15Hz, with which we demodulate the AM signal. */ + v1 = fabs(famp) + 1.996667f*s->z15hz_1 - 0.9968004f*s->z15hz_2; + filtered = 0.001599787f*(v1 - s->z15hz_2); + s->z15hz_2 = s->z15hz_1; + s->z15hz_1 = v1; + s->am_level += abs(lfastrintf(filtered)) - (s->am_level >> 8); + //printf("%9.1f %10.4f %9d %9d\n", famp, filtered, s->am_level, s->channel_level); /* A Cauer notch at 2100Hz, spread just wide enough to meet our detection bandwidth criteria. */ /* This is actually centred at 2095Hz, but gets the balance we want, due to the asymmetric walls of the notch */ - famp = amp[i]; - v1 = 0.76000f*famp - 0.1183852f*s->z1 - 0.5104039f*s->z2; - famp = v1 + 0.1567596f*s->z1 + s->z2; - s->z2 = s->z1; - s->z1 = v1; + v1 = 0.76000f*famp - 0.1183852f*s->znotch_1 - 0.5104039f*s->znotch_2; + famp = v1 + 0.1567596f*s->znotch_1 + s->znotch_2; + s->znotch_2 = s->znotch_1; + s->znotch_1 = v1; notched = (int16_t) lfastrintf(famp); /* Estimate the overall energy in the channel, and the energy in the notch (i.e. overall channel energy - tone energy => noise). Use abs instead of multiply for speed (is it really faster?). Damp the overall energy a little more for a stable result. Damp the notch energy a little less, so we don't damp out the - blip every time the phase reverses */ + blip every time the phase reverses. */ s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); s->notch_level += ((abs(notched) - s->notch_level) >> 4); /* This should cut off at about -43dBm0 */ @@ -455,7 +495,11 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * if (s->tone_cycle_duration >= ms_to_samples(450 - 25)) { if (++s->good_cycles == 3) - report_tone_state(s, MODEM_CONNECT_TONES_ANS_PR, lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); + { + report_tone_state(s, + (s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM_PR : MODEM_CONNECT_TONES_ANS_PR, + lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); + } } else { @@ -466,17 +510,21 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * } else { - if (s->tone_cycle_duration >= ms_to_samples(550)) + if (s->tone_cycle_duration >= ms_to_samples(450 + 100)) { if (s->tone_present == MODEM_CONNECT_TONES_NONE) - report_tone_state(s, MODEM_CONNECT_TONES_ANS, lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); + { + report_tone_state(s, + (s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM : MODEM_CONNECT_TONES_ANS, + lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); + } s->good_cycles = 0; - s->tone_cycle_duration = ms_to_samples(550); + s->tone_cycle_duration = ms_to_samples(450 + 100); } } s->tone_on = TRUE; } - else + else if (s->notch_level*5 > s->channel_level) { if (s->tone_present == MODEM_CONNECT_TONES_ANS) { @@ -528,7 +576,7 @@ SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem { case MODEM_CONNECT_TONES_FAX_PREAMBLE: case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: - fsk_rx_init(&(s->v21rx), &preset_fsk_specs[FSK_V21CH2], TRUE, v21_put_bit, s); + fsk_rx_init(&(s->v21rx), &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, s); fsk_rx_signal_cutoff(&(s->v21rx), -45.5f); break; case MODEM_CONNECT_TONES_ANS_PR: @@ -540,6 +588,7 @@ SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem } s->channel_level = 0; s->notch_level = 0; + s->am_level = 0; s->tone_present = MODEM_CONNECT_TONES_NONE; s->tone_cycle_duration = 0; s->good_cycles = 0; @@ -547,8 +596,10 @@ SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem s->tone_on = FALSE; s->tone_callback = tone_callback; s->callback_data = user_data; - s->z1 = 0.0f; - s->z2 = 0.0f; + s->znotch_1 = 0.0f; + s->znotch_2 = 0.0f; + s->z15hz_1 = 0.0f; + s->z15hz_2 = 0.0f; s->num_bits = 0; s->flags_seen = 0; s->framing_ok_announced = FALSE; diff --git a/libs/spandsp/src/msvc/spandsp.h b/libs/spandsp/src/msvc/spandsp.h index 25f705f5ab..4e06660bdf 100644 --- a/libs/spandsp/src/msvc/spandsp.h +++ b/libs/spandsp/src/msvc/spandsp.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: spandsp.h.in,v 1.19 2009/09/22 13:11:04 steveu Exp $ + * $Id: spandsp.h.in,v 1.19.4.1 2009/12/19 09:47:56 steveu Exp $ */ /*! \file */ @@ -99,7 +99,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/libs/spandsp/src/spandsp.h.in b/libs/spandsp/src/spandsp.h.in index 59122b654f..3293bb5027 100644 --- a/libs/spandsp/src/spandsp.h.in +++ b/libs/spandsp/src/spandsp.h.in @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: spandsp.h.in,v 1.19 2009/09/22 13:11:04 steveu Exp $ + * $Id: spandsp.h.in,v 1.19.4.1 2009/12/19 09:47:56 steveu Exp $ */ /*! \file */ @@ -96,7 +96,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/libs/spandsp/src/spandsp/expose.h b/libs/spandsp/src/spandsp/expose.h index 44a3c5c7b5..da14722aae 100644 --- a/libs/spandsp/src/spandsp/expose.h +++ b/libs/spandsp/src/spandsp/expose.h @@ -23,7 +23,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: expose.h,v 1.14 2009/09/22 13:11:04 steveu Exp $ + * $Id: expose.h,v 1.14.4.1 2009/12/19 09:47:56 steveu Exp $ */ /*! \file */ @@ -71,7 +71,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/libs/spandsp/src/spandsp/fsk.h b/libs/spandsp/src/spandsp/fsk.h index 8bec2fbb10..854d9e6a22 100644 --- a/libs/spandsp/src/spandsp/fsk.h +++ b/libs/spandsp/src/spandsp/fsk.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: fsk.h,v 1.40 2009/06/02 16:03:56 steveu Exp $ + * $Id: fsk.h,v 1.41 2009/11/02 13:25:20 steveu Exp $ */ /*! \file */ @@ -115,6 +115,15 @@ enum FSK_WEITBRECHT50 /* 50 baud version, used for TDD (Telecom Device for the Deaf) */ }; +enum +{ + FSK_FRAME_MODE_ASYNC = 0, + FSK_FRAME_MODE_SYNC = 1, + FSK_FRAME_MODE_5N1_FRAMES = 7, /* 5 bits of data + start bit + stop bit */ + FSK_FRAME_MODE_7N1_FRAMES = 9, /* 7 bits of data + start bit + stop bit */ + FSK_FRAME_MODE_8N1_FRAMES = 10 /* 8 bits of data + start bit + stop bit */ +}; + SPAN_DECLARE_DATA extern const fsk_spec_t preset_fsk_specs[]; /*! @@ -149,6 +158,8 @@ SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s, get_bit_func_t get_bit, void *user_data); +SPAN_DECLARE(int) fsk_tx_restart(fsk_tx_state_t *s, const fsk_spec_t *spec); + SPAN_DECLARE(int) fsk_tx_release(fsk_tx_state_t *s); SPAN_DECLARE(int) fsk_tx_free(fsk_tx_state_t *s); @@ -203,6 +214,8 @@ SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s, put_bit_func_t put_bit, void *user_data); +SPAN_DECLARE(int) fsk_rx_restart(fsk_rx_state_t *s, const fsk_spec_t *spec, int framing_mode); + SPAN_DECLARE(int) fsk_rx_release(fsk_rx_state_t *s); SPAN_DECLARE(int) fsk_rx_free(fsk_rx_state_t *s); diff --git a/libs/spandsp/src/spandsp/private/modem_connect_tones.h b/libs/spandsp/src/spandsp/private/modem_connect_tones.h index 6d80f74b13..331402c1e4 100644 --- a/libs/spandsp/src/spandsp/private/modem_connect_tones.h +++ b/libs/spandsp/src/spandsp/private/modem_connect_tones.h @@ -24,7 +24,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: modem_connect_tones.h,v 1.2 2009/01/29 18:30:14 steveu Exp $ + * $Id: modem_connect_tones.h,v 1.3 2009/11/02 13:25:20 steveu Exp $ */ /*! \file */ @@ -66,12 +66,17 @@ struct modem_connect_tones_rx_state_s void *callback_data; /*! \brief The notch filter state. */ - float z1; - float z2; + float znotch_1; + float znotch_2; + /*! \brief The 15Hz AM filter state. */ + float z15hz_1; + float z15hz_2; /*! \brief The in notch power estimate */ - int notch_level; + int32_t notch_level; /*! \brief The total channel power estimate */ - int channel_level; + int32_t channel_level; + /*! \brief The 15Hz AM power estimate */ + int32_t am_level; /*! \brief Sample counter for the small chunks of samples, after which a test is conducted. */ int chunk_remainder; /*! \brief TRUE is the tone is currently confirmed present in the audio. */ diff --git a/libs/spandsp/src/spandsp/private/t30.h b/libs/spandsp/src/spandsp/private/t30.h index 958a553c89..64ae2c5fd5 100644 --- a/libs/spandsp/src/spandsp/private/t30.h +++ b/libs/spandsp/src/spandsp/private/t30.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t30.h,v 1.5 2009/09/20 13:42:29 steveu Exp $ + * $Id: t30.h,v 1.5.4.1 2009/12/19 09:47:56 steveu Exp $ */ /*! \file */ @@ -253,7 +253,7 @@ struct t30_state_s int tx_stop_page; /*! \brief The current completion status. */ int current_status; - /*! \brief Internet Aware FAX mode bit mask. */ + /*! \brief Internet aware FAX mode bit mask. */ int iaf; /*! \brief A bit mask of the currently supported modem types. */ int supported_modems; diff --git a/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h b/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h new file mode 100644 index 0000000000..7db4df98e9 --- /dev/null +++ b/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h @@ -0,0 +1,387 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * t30_dis_dtc_dcs_bits.h - ITU T.30 fax control bits definitions + * + * Written by Steve Underwood + * + * Copyright (C) 2009 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: t30_dis_dtc_dcs_bits.h,v 1.1.4.1 2009/12/19 09:47:57 steveu Exp $ + */ + +/*! \file */ + +#if !defined(_SPANDSP_PRIVATE_T30_DIS_DTC_DCS_BITS_H_) +#define _SPANDSP_PRIVATE_T30_DIS_DTC_DCS_BITS_H_ + +/* Indicates that the terminal has the Simple mode capability defined in ITU-T Rec. T.37. + Internet address signals CIA, TSA or CSA can be sent and received. The recipient terminal + may process or ignore this signal. */ +#define T30_DIS_BIT_T37 1 +#define T30_DCS_BIT_T37 1 + +/* Indicates that the terminal has the capability to communicate using ITU-T Rec. T.38. + Internet address signals CIA, TSA or CSA can be sent and received. The recipient terminal + may process or ignore this signal. */ +#define T30_DIS_BIT_T38 3 +#define T30_DCS_BIT_T38 3 + +/* Bit 4 set to "1" indicates 3rd Generation Mobile Network Access to the GSTN Connection. + Bit 4 set to "0" conveys no information about the type of connection. */ +#define T30_DIS_BIT_3G_MOBILE 4 +#define T30_DCS_BIT_3G_MOBILE 4 + +/* When ISDN mode is used, in DIS/DTC bit 6 shall be set to "0". */ +#define T30_DIS_BIT_V8_CAPABILITY 6 + +/* When ISDN mode is used, in DIS/DTC bit 7 shall be set to "0". */ +#define T30_DIS_BIT_64_OCTET_ECM_FRAMES_PREFERRED 7 + +/* Bit 9 indicates that there is a facsimile document ready to be polled from the answering + terrminal. It is not an indication of a capability. */ +#define T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT 9 + +/* In DIS/DTC bit 10 indicates that the answering terminal has receiving capabilities. + In DCS it is a command to the receiving terminal to set itself in the receive mode. */ +#define T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT 10 +#define T30_DCS_BIT_RECEIVE_FAX_DOCUMENT 10 + +/* Bits 11, 12, 13, 14 - modem type */ + +#define T30_DIS_BIT_200_200_CAPABLE 15 +#define T30_DCS_BIT_200_200 15 + +#define T30_DIS_BIT_2D_CAPABLE 16 +#define T30_DCS_BIT_2D_CODING 16 + +/* Standard facsimile terminals conforming to ITU-T Rec. T.4 must have the following capability: + Paper length = 297 mm. */ + +/* Bits 17, 18 - recording width */ + +/* Bits 19, 20 - paper length */ + +/* Bits 21, 22, 23 - min scan line time */ + +/* When ISDN mode is used, in DIS/DTC bits 21 to 23 shall be set to "1". */ + +#define T30_DIS_BIT_UNCOMPRESSED_CAPABLE 26 +#define T30_DCS_BIT_UNCOMPRESSED_MODE 26 + +/* When ISDN mode is used, in DIS/DTC bit 27 shall be set to "1". */ +#define T30_DIS_BIT_ECM_CAPABLE 27 +#define T30_DCS_BIT_ECM 27 + +/* The value of bit 28 in the DCS command is only valid when ECM is selected. */ +#define T30_DCS_BIT_64_OCTET_ECM_FRAMES 28 + +/* The value of bit 31 in the DCS command is only valid when ECM is selected. */ +#define T30_DIS_BIT_T6_CAPABLE 31 +#define T30_DCS_BIT_T6_MODE 31 + +#define T30_DIS_BIT_FNV_CAPABLE 33 +#define T30_DCS_BIT_FNV_CAPABLE 33 + +#define T30_DIS_BIT_MULTIPLE_SELECTIVE_POLLING_CAPABLE 34 + +#define T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE 35 + +#define T30_DIS_BIT_T43_CAPABLE 36 +#define T30_DCS_BIT_T43_CODING 36 + +#define T30_DIS_BIT_PLANE_INTERLEAVE_CAPABLE 37 +#define T30_DCS_BIT_PLANE_INTERLEAVE 37 + +#define T30_DIS_BIT_G726_CAPABLE 38 +#define T30_DCS_BIT_G726 38 + +#define T30_DIS_BIT_200_400_CAPABLE 41 +#define T30_DCS_BIT_200_400 41 + +#define T30_DIS_BIT_300_300_CAPABLE 42 +#define T30_DCS_BIT_300_300 42 + +#define T30_DIS_BIT_400_400_CAPABLE 43 +#define T30_DCS_BIT_400_400 43 + +/* Bits 44 and 45 are used only in conjunction with bits 15 and 43. Bit 44 in DCS, when used, + shall correctly indicate the resolution of the transmitted document, which means that bit 44 in DCS may + not always match the indication of bits 44 and 45 in DIS/DTC. Cross selection will cause the distortion + and reduction of reproducible area. + If a receiver indicates in DIS that it prefers to receive metric-based information, but the transmitter has + only the equivalent inch-based information (or vice versa), then communication shall still take place. + Bits 44 and 45 do not require the provision of any additional features on the terminal to + indicate to the sending or receiving user whether the information was transmitted or received on a metric-metric, + inch-inch, metric-inch, inch-metric basis. */ + +#define T30_DIS_BIT_INCH_RESOLUTION_PREFERRED 44 +#define T30_DCS_BIT_INCH_RESOLUTION 44 + +#define T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED 45 + +#define T30_DIS_BIT_MIN_SCAN_TIME_HALVES 46 + +#define T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE 47 + +#define T30_DIS_BIT_SUBADDRESSING_CAPABLE 49 +#define T30_DCS_BIT_SUBADDRESS_TRANSMISSION 49 + +#define T30_DIS_BIT_PASSWORD 50 +#define T30_DCS_BIT_SENDER_ID_TRANSMISSION 50 + +/* Bit 51 indicates that there is a data file ready to be polled from the answering terminal. It is + not an indication of a capability. This bit is used in conjunction with bits 53, 54, 55 and 57. */ +#define T30_DIS_BIT_READY_TO_TRANSMIT_DATA_FILE 51 + +/* The binary file transfer protocol is described in ITU-T Rec. T.434. */ +#define T30_DIS_BIT_BFT_CAPABLE 53 +#define T30_DCS_BIT_BFT 53 + +#define T30_DIS_BIT_DTM_CAPABLE 54 +#define T30_DCS_BIT_DTM 54 + +#define T30_DIS_BIT_EDI_CAPABLE 55 +#define T30_DCS_BIT_EDI 55 + +#define T30_DIS_BIT_BTM_CAPABLE 57 +#define T30_DCS_BIT_BTM 57 + +/* Bit 59 indicates that there is a character-coded or mixed-mode document ready to be polled + from the answering terminal. It is not an indication of a capability. This bit is used in + conjunction with bits 60, 62 and 65. */ +#define T30_DIS_BIT_READY_TO_TRANSMIT_MIXED_MODE_DOCUMENT 59 + +#define T30_DIS_BIT_CHARACTER_MODE 60 +#define T30_DCS_BIT_CHARACTER_MODE 60 + +#define T30_DIS_BIT_MIXED_MODE 62 +#define T30_DCS_BIT_MIXED_MODE 62 + +#define T30_DIS_BIT_PROCESSABLE_MODE_26 65 + +#define T30_DIS_BIT_DIGITAL_NETWORK_CAPABLE 66 +#define T30_DCS_BIT_DIGITAL_NETWORK_CAPABLE 66 + +#define T30_DIS_BIT_DUPLEX_CAPABLE 67 +#define T30_DCS_BIT_DUPLEX_CAPABLE 67 + +#define T30_DIS_BIT_T81_CAPABLE 68 +#define T30_DCS_BIT_FULL_COLOUR_MODEX 68 + +#define T30_DIS_BIT_FULL_COLOUR_CAPABLE 69 +#define T30_DCS_BIT_FULL_COLOUR_MODE 69 + +/* In a DIS/DTC frame, setting bit 71 to "0" indicates that the called terminal can only accept + image data which has been digitized to 8 bits/pel/component for JPEG mode. This is also true for T.43 + mode if bit 36 is also set to "1". Setting bit 71 to "1" indicates that the called terminal can also accept + image data that are digitized to 12 bits/pel/component for JPEG mode. This is also true for T.43 mode if + bit 36 is also set to "1". In a DCS frame, setting bit 71 to "0" indicates that the calling terminal's image + data are digitized to 8 bits/pel/component for JPEG mode. This is also true for T.43 mode if bit 36 is also + set to "1". Setting bit 71 to "1" indicates that the calling terminal transmits image data which has been + digitized to 12 bits/pel/component for JPEG mode. This is also true for T.43 mode if bit 36 is also set + to "1". */ +#define T30_DIS_BIT_12BIT_CAPABLE 71 +#define T30_DCS_BIT_12BIT_COMPONENT 71 + +#define T30_DIS_BIT_NO_SUBSAMPLING 73 +#define T30_DCS_BIT_NO_SUBSAMPLING 73 + +#define T30_DIS_BIT_CUSTOM_ILLUMINANT 74 +#define T30_DCS_BIT_CUSTOM_ILLUMINANT 74 + +#define T30_DIS_BIT_CUSTOM_GAMUT_RANGE 75 +#define T30_DCS_BIT_CUSTOM_GAMUT_RANGE 75 + +#define T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE 76 +#define T30_DCS_BIT_NORTH_AMERICAN_LETTER 76 + +#define T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE 77 +#define T30_DCS_BIT_NORTH_AMERICAN_LEGAL 77 + +#define T30_DIS_BIT_T85_CAPABLE 78 +#define T30_DCS_BIT_T85_MODE 78 + +#define T30_DIS_BIT_T85_L0_CAPABLE 79 +#define T30_DCS_BIT_T85_L0_MODE 79 + +/* In a DIS/DTC frame, setting bit 97 to "0" indicates that the called terminal does not have the + capability to accept 300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm + resolutions for colour/gray-scale images or T.44 Mixed Raster Content (MRC) mask layer. + + Setting bit 97 to "1" indicates that the called terminal does have the capability to accept + 300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm resolutions for + colour/gray-scale images and MRC mask layer. Bit 97 is valid only when bits 68 and 42 or 43 + (300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm) are set to "1". + + In a DCS frame, setting bit 97 to "0" indicates that the calling terminal does not use + 300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm resolutions + for colour/gray-scale images and mask layer. + + Setting bit 97 to "1" indicates that the calling terminal uses 300 pels/25.4 mm x 300 lines/25.4 mm + or 400 pels/25.4 mm x 400 lines/25.4 mm resolutions for colour/gray-scale images and MRC mask layer. + Bit 97 is valid only when bits 68 and 42 or 43 (300 pels/25.4 mm x 300 lines/25.4 mm and + 400 pels/25.4 mm x 400 lines/25.4 mm) are set to "1". + + In a DIS/DTC frame, combinations of bit 42, bit 43 and bit 97 indicate that the called terminal + has higher resolution capabilities as follows: + + Resolution capabilities (pels/25.4 mm) + DIS/DTC Monochrome Colour/gray-scale + 42 43 97 300 x 300 400 x 400 300 x 300 400 x 400 + 0 0 0 no no no no + 1 0 0 yes no no no + 0 1 0 no yes no no + 1 1 0 yes yes no no + 0 0 1 (invalid) + 1 0 1 yes no yes no + 0 1 1 no yes no yes + 1 1 1 yes yes yes yes + "yes" means that the called terminal has the corresponding capability. + "no" means that the called terminal does not have the corresponding capability. */ +#define T30_DIS_BIT_COLOUR_GREY_300_300_400_400_CAPABLE 97 +#define T30_DCS_BIT_COLOUR_GREY_300_300_400_400 97 + +/* In a DIS/DTC frame, setting bit 98 to "0" indicates that the called terminal does not have the + capability to accept 100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale + images. Setting bit 98 to "1" indicates that the called terminal does have the capability to accept + 100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale images. Bit 98 is valid + only when bit 68 is set to "1". In a DCS frame, setting bit 98 to "0" indicates that the calling terminal does + not use 100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale images. Setting + bit 98 to "1" indicates that the calling terminal uses 100 pels/25.4 mm x 100 lines/25.4 mm spatial + resolution for colour or gray-scale images. */ +#define T30_DIS_BIT_COLOUR_GREY_100_100_CAPABLE 98 +#define T30_DCS_BIT_COLOUR_GREY_100_100 98 + +/* To provide an error recovery mechanism, when PWD/SEP/SUB/SID/PSA/IRA/ISP frames are sent with DCS or DTC, + bits 49, 102 and 50 in DCS or bits 47, 101, 50 and 35 in DTC shall be set to "1" with the following + meaning: + Bit DIS DTC DCS + 35 Polled SubAddress capability Polled SubAddress transmission Not allowed – set to "0" + 47 Selective polling capability Selective polling transmission Not allowed – set to "0" + 49 Subaddressing capability Not allowed (Set to "0") Subaddressing transmission + 50 Password Password transmission Sender Identification transmission + 101 Internet Selective Polling Address capability Internet Selective Polling Address transmission Not allowed – set to "0" + 102 Internet Routing Address capability Not allowed (Set to "0") Internet Routing Address transmission + + Terminals conforming to the 1993 version of T.30 may set the above bits to "0" even though PWD/SEP/SUB + frames are transmitted. */ +#define T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS 101 + +#define T30_DIS_BIT_INTERNET_ROUTING_ADDRESS 102 +#define T30_DCS_BIT_INTERNET_ROUTING_ADDRESS_TRANSMISSION 102 + +#define T30_DIS_BIT_600_600_CAPABLE 105 +#define T30_DCS_BIT_600_600 105 + +#define T30_DIS_BIT_1200_1200_CAPABLE 106 +#define T30_DCS_BIT_1200_1200 106 + +#define T30_DIS_BIT_300_600_CAPABLE 107 +#define T30_DCS_BIT_300_600 107 + +#define T30_DIS_BIT_400_800_CAPABLE 108 +#define T30_DCS_BIT_400_800 108 + +#define T30_DIS_BIT_600_1200_CAPABLE 109 +#define T30_DCS_BIT_600_1200 109 + +#define T30_DIS_BIT_COLOUR_GREY_600_600_CAPABLE 110 +#define T30_DCS_BIT_COLOUR_GREY_600_600 110 + +#define T30_DIS_BIT_COLOUR_GREY_1200_1200_CAPABLE 111 +#define T30_DCS_BIT_COLOUR_GREY_1200_1200 111 + +#define T30_DIS_BIT_ALTERNATE_DOUBLE_SIDED_CAPABLE 113 +#define T30_DCS_BIT_ALTERNATE_DOUBLE_SIDED_CAPABLE 113 + +#define T30_DIS_BIT_CONTINUOUS_DOUBLE_SIDED_CAPABLE 114 +#define T30_DCS_BIT_CONTINUOUS_DOUBLE_SIDED_CAPABLE 114 + +#define T30_DIS_BIT_BLACK_AND_WHITE_MRC 115 + +#define T30_DIS_BIT_T45_CAPABLE 116 +#define T30_DCS_BIT_T45_MODE 116 + +/* This bit defines the available colour space, when bit 92, 93 or 94 is set to "1". + Available colour space for all combinations of bits 92, 93, 94 and 119 are shown in the following table. + It should be noted that terminals which conform to the 2003 and earlier versions of this Recommendation + will send LAB with "1" in bit 92, 93 or 94 even if bit 119 is set to "1". + + Available colour space for DIS/DTC bits 92, 93, 94 and 119 + + 92 93 94 119 Mode of T.44 Available colour space + 0 0 0 x Not available - + 1 0 0 0 Mode 1 LAB only + 1 0 0 1 Mode 1 YCC only + x 1 x 0 Mode 2 or higher LAB only + x x 1 0 Mode 2 or higher LAB only + x 1 x 1 Mode 2 or higher LAB and YCC + x x 1 1 Mode 2 or higher LAB and YCC + + Colour space for DCS bits 92, 93, 94 and 119 + + 92 93 94 119 Mode of T.44 Colour space + 0 0 0 x* Not available - + 1 0 0 0 Mode 1 LAB + 1 0 0 1 Mode 1 YCC + x 1 x 0 Mode 2 or higher LAB + x x 1 0 Mode 2 or higher LAB + x 1 x 1 Mode 2 or higher YCC or mixing of YCC and LAB + x x 1 1 Mode 2 or higher YCC or mixing of YCC and LAB */ +#define T30_DIS_BIT_T44_COLOUR_SPACE 119 +#define T30_DCS_BIT_T44_COLOUR_SPACE 119 + +/* Can only be set in the communication through the T.38 gateway, to cope with delay of network. + T.x timer (12+-1s) should be used after emitting RNR or TNR. However, after receiving + PPS signal in ECM mode, T.5 timer should be used. */ +#define T30_DIS_BIT_T38_FLOW_CONTROL_CAPABLE 121 +#define T30_DCS_BIT_T38_FLOW_CONTROL_CAPABLE 121 + +/* For resolutions greater than 200 lines/25.4 mm, 4.2.1.1/T.4 specifies the use of specific K + factors for each standardized vertical resolution. To ensure backward compatibility with earlier + versions of ITU-T Rec. T.4, bit 122 indicates when such K factors are being used. */ +#define T30_DIS_BIT_K_GREATER_THAN_4 122 + +/* This bit should be set to "1" if the fax device is an Internet-Aware Fax Device as defined in + ITU-T Rec. T.38 and if it is not affected by the data signal rate indicated by the DIS and DTC + signals when communicating with another Internet-Aware Fax Device operating in T.38 mode. This + bit shall not be used in GSTN mode. */ +#define T30_DIS_BIT_T38_FAX_CAPABLE 123 +/* This bit should be set to "1" if the fax device elects to operate in an Internet-Aware Fax mode + as defined in ITU-T Rec. T.38 in response to a device which has set the related DIS bit to "1". + When this bit is set to "1", the data signal rate of the modem (bits 11-14) should be set to "0". */ +#define T30_DCS_BIT_T38_FAX_MODE 123 + +/* When either bit of 31, 36, 38, 51, 53, 54, 55, 57, 59, 60, 62, 65, 68, 78, 79, 115, 116 and 127 is + set to "1", ECM must be used. If the value of bit field 92 to 94 is non-zero, then ECM must be used. + + Annex K describes the optional continuous-tone colour and gray scale images mode + (sYCC-JPEG mode) protocol. When bit 127 in DIS/DTC frame is set to "1", the called terminal has the + capability to accept sYCC-JPEG mode. This is defined with complete independent in the colour space + CIELAB. In addition, when bit 127 in DCS frame is set to "1", ECM must be used and bits 15, 17, 18, + 19, 20, 41, 42, 43, 45, 46, 68, 69, 71, 73, 74, 75, 76, 77, 97, 98, 105, 106, 107, 108, + 109, 110 and 111 in DCS frame are "Don't care", and should be set to "0". In the case of + transmission of multiple images, a post message signal PPS-MPS between pages, PPS-NULL between + partial pages and PPS-EOP following the last page should be sent from the calling terminal to the + called terminal. */ +#define T30_DIS_BIT_SYCC_T81_CAPABLE 127 +#define T30_DCS_BIT_SYCC_T81_MODE 127 + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t38_gateway.h b/libs/spandsp/src/spandsp/private/t38_gateway.h index be2dd1caa0..9f4eed57e0 100644 --- a/libs/spandsp/src/spandsp/private/t38_gateway.h +++ b/libs/spandsp/src/spandsp/private/t38_gateway.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_gateway.h,v 1.4 2009/05/16 03:34:45 steveu Exp $ + * $Id: t38_gateway.h,v 1.5 2009/11/07 08:58:58 steveu Exp $ */ /*! \file */ @@ -163,8 +163,8 @@ typedef struct int ecm_mode; /*! \brief The current bit rate for the fast modem. */ int fast_bit_rate; - /*! \brief The current fast modem type. */ - int fast_modem; + /*! \brief The current fast receive modem type. */ + int fast_rx_modem; /*! \brief The type of fast receive modem currently active, which may be T38_NONE */ int fast_rx_active; diff --git a/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h b/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h index 9b66faf7f6..247233f58e 100644 --- a/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h +++ b/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h @@ -23,7 +23,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_non_ecm_buffer.h,v 1.2 2008/10/13 14:19:18 steveu Exp $ + * $Id: t38_non_ecm_buffer.h,v 1.2.4.1 2009/12/19 06:43:28 steveu Exp $ */ #if !defined(_SPANDSP_PRIVATE_T38_NON_ECM_BUFFER_H_) @@ -36,7 +36,7 @@ struct t38_non_ecm_buffer_state_s { /*! \brief Minimum number of bits per row, used when fill bits are being deleted on the link, and restored at the emitting gateway. */ - int min_row_bits; + int min_bits_per_row; /*! \brief non-ECM modem transmit data buffer. */ uint8_t data[T38_NON_ECM_TX_BUF_LEN]; @@ -55,8 +55,8 @@ struct t38_non_ecm_buffer_state_s /*! \brief The non-ECM flow control fill octet (0xFF before the first data, and 0x00 once data has started). */ uint8_t flow_control_fill_octet; - /*! \brief TRUE if we are in the initial all ones part of non-ECM transmission. */ - int at_initial_all_ones; + /*! \brief A code for the phase of input buffering, from initial all ones to completion. */ + int input_phase; /*! \brief TRUE is the end of non-ECM data indication has been received. */ int data_finished; /*! \brief The current octet being transmitted from the buffer. */ diff --git a/libs/spandsp/src/spandsp/private/t4_rx.h b/libs/spandsp/src/spandsp/private/t4_rx.h new file mode 100644 index 0000000000..6511ace1f8 --- /dev/null +++ b/libs/spandsp/src/spandsp/private/t4_rx.h @@ -0,0 +1,131 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/t4_rx.h - definitions for T.4 FAX receive processing + * + * Written by Steve Underwood + * + * Copyright (C) 2003 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: t4_rx.h,v 1.6.2.8 2009/12/21 17:18:40 steveu Exp $ + */ + +#if !defined(_SPANDSP_PRIVATE_T4_RX_H_) +#define _SPANDSP_PRIVATE_T4_RX_H_ + +/*! + TIFF specific state information to go with T.4 compression or decompression handling. +*/ +typedef struct +{ + /*! \brief The current file name. */ + const char *file; + /*! \brief The libtiff context for the current TIFF file */ + TIFF *tiff_file; + + /*! \brief The number of pages in the current image file. */ + int pages_in_file; + + /*! \brief The compression type for output to the TIFF file. */ + int32_t output_compression; + /*! \brief The TIFF photometric setting for the current page. */ + uint16_t photo_metric; + /*! \brief The TIFF fill order setting for the current page. */ + uint16_t fill_order; + /*! \brief The TIFF G3 FAX options. */ + int32_t output_t4_options; + + /* "Background" information about the FAX, which can be stored in the image file. */ + /*! \brief The vendor of the machine which produced the file. */ + const char *vendor; + /*! \brief The model of machine which produced the file. */ + const char *model; + /*! \brief The local ident string. */ + const char *local_ident; + /*! \brief The remote end's ident string. */ + const char *far_ident; + /*! \brief The FAX sub-address. */ + const char *sub_address; + /*! \brief The FAX DCS information, as an ASCII string. */ + const char *dcs; + + /*! \brief The first page to transfer. -1 to start at the beginning of the file. */ + int start_page; + /*! \brief The last page to transfer. -1 to continue to the end of the file. */ + int stop_page; +} t4_tiff_state_t; + +typedef struct t4_t6_decode_state_s t4_t6_decode_state_t; + +/*! + T.4 1D, T4 2D and T6 decompressor state. +*/ +struct t4_t6_decode_state_s +{ + /*! \brief Callback function to write a row of pixels to the image destination. */ + t4_row_write_handler_t row_write_handler; + /*! \brief Opaque pointer passed to row_write_handler. */ + void *row_write_user_data; + + /*! \brief Incoming bit buffer for decompression. */ + uint32_t rx_bitstream; + /*! \brief The number of bits currently in rx_bitstream. */ + int rx_bits; + /*! \brief The number of bits to be skipped before trying to match the next code word. */ + int rx_skip_bits; + + /*! \brief This variable is used to count the consecutive EOLS we have seen. If it + reaches six, this is the end of the image. It is initially set to -1 for + 1D and 2D decoding, as an indicator that we must wait for the first EOL, + before decoding any image data. */ + int consecutive_eols; + + /*! \brief The reference or starting changing element on the coding line. At the + start of the coding line, a0 is set on an imaginary white changing element + situated just before the first element on the line. During the coding of + the coding line, the position of a0 is defined by the previous coding mode. + (See T.4/4.2.1.3.2.). */ + int a0; + /*! \brief The first changing element on the reference line to the right of a0 and of + opposite colour to a0. */ + int b1; + /*! \brief The length of the in-progress run of black or white. */ + int run_length; + /*! \brief 2D horizontal mode control. */ + int black_white; + /*! \brief TRUE if the current run is black */ + int its_black; + + /*! \brief The current step into the current row run-lengths buffer. */ + int a_cursor; + /*! \brief The current step into the reference row run-lengths buffer. */ + int b_cursor; + + /*! \brief A pointer into the image buffer indicating where the last row begins */ + int last_row_starts_at; + + /*! \brief The current number of consecutive bad rows. */ + int curr_bad_row_run; + /*! \brief The longest run of consecutive bad rows seen in the current page. */ + int longest_bad_row_run; + /*! \brief The total number of bad rows in the current page. */ + int bad_rows; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t4_tx.h b/libs/spandsp/src/spandsp/private/t4_tx.h new file mode 100644 index 0000000000..a65d0b4155 --- /dev/null +++ b/libs/spandsp/src/spandsp/private/t4_tx.h @@ -0,0 +1,142 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/t4_tx.h - definitions for T.4 FAX transmit processing + * + * Written by Steve Underwood + * + * Copyright (C) 2003 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: t4_tx.h,v 1.7.2.4 2009/12/21 17:18:40 steveu Exp $ + */ + +#if !defined(_SPANDSP_PRIVATE_T4_TX_H_) +#define _SPANDSP_PRIVATE_T4_TX_H_ + +typedef struct t4_t6_encode_state_s t4_t6_encode_state_t; + +/*! + T.4 1D, T4 2D and T6 compressor state. +*/ +struct t4_t6_encode_state_s +{ + /*! \brief The minimum number of encoded bits per row. This is a timing thing + for hardware FAX machines. */ + int min_bits_per_row; + /*! \brief The current maximum contiguous rows that may be 2D encoded. */ + int max_rows_to_next_1d_row; + + /*! \brief The text which will be used in FAX page header. No text results + in no header line. */ + const char *header_info; + + /*! \brief Number of rows left that can be 2D encoded, before a 1D encoded row + must be used. */ + int rows_to_next_1d_row; + + /*! \brief The number of runs currently in the reference row. */ + int ref_steps; + + /*! \brief Pointer to the byte containing the next image bit to transmit. */ + int bit_pos; + /*! \brief Pointer to the bit within the byte containing the next image bit to transmit. */ + int bit_ptr; + + /*! \brief Callback function to read a row of pixels from the image source. */ + t4_row_read_handler_t row_read_handler; + /*! \brief Opaque pointer passed to row_read_handler. */ + void *row_read_user_data; +}; + +/*! + T.4 FAX compression/decompression descriptor. This defines the working state + for a single instance of a T.4 FAX compression or decompression channel. +*/ +struct t4_state_s +{ + /*! \brief The same structure is used for T.4 transmit and receive. This variable + records which mode is in progress. */ + int rx; + + /*! \brief The type of compression used between the FAX machines. */ + int line_encoding; + + /*! \brief The time at which handling of the current page began. */ + time_t page_start_time; + + /*! \brief The size of the compressed image on the line side, in bits. */ + int line_image_size; + + /*! \brief The current number of bytes per row of uncompressed image data. */ + int bytes_per_row; + /*! \brief The size of the image in the image buffer, in bytes. */ + int image_size; + /*! \brief The current size of the image buffer. */ + int image_buffer_size; + /*! \brief A point to the image buffer. */ + uint8_t *image_buffer; + + /*! \brief The number of pages transferred to date. */ + int current_page; + /*! \brief Column-to-column (X) resolution in pixels per metre. */ + int x_resolution; + /*! \brief Row-to-row (Y) resolution in pixels per metre. */ + int y_resolution; + /*! \brief Width of the current page, in pixels. */ + int image_width; + /*! \brief Length of the current page, in pixels. */ + int image_length; + /*! \brief Current pixel row number. */ + int row; + + /*! \brief This variable is set if we are treating the current row as a 2D encoded + one. */ + int row_is_2d; + /*! \brief The current length of the current row. */ + int row_len; + + /*! \brief Black and white run-lengths for the current row. */ + uint32_t *cur_runs; + /*! \brief Black and white run-lengths for the reference row. */ + uint32_t *ref_runs; + /*! \brief Pointer to the buffer for the current pixel row. */ + uint8_t *row_buf; + + /*! \brief Encoded data bits buffer. */ + uint32_t tx_bitstream; + /*! \brief The number of bits currently in tx_bitstream. */ + int tx_bits; + + /*! \brief The current number of bits in the current encoded row. */ + int row_bits; + /*! \brief The minimum bits in any row of the current page. For monitoring only. */ + int min_row_bits; + /*! \brief The maximum bits in any row of the current page. For monitoring only. */ + int max_row_bits; + + /*! \brief Error and flow logging control */ + logging_state_t logging; + + /*! \brief All TIFF file specific state information for the T.4 context. */ + t4_tiff_state_t tiff; + t4_t6_decode_state_t t4_t6_rx; + t4_t6_encode_state_t t4_t6_tx; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v18.h b/libs/spandsp/src/spandsp/private/v18.h index 5767158f37..79471fd68f 100644 --- a/libs/spandsp/src/spandsp/private/v18.h +++ b/libs/spandsp/src/spandsp/private/v18.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v18.h,v 1.4 2009/04/11 15:16:14 steveu Exp $ + * $Id: v18.h,v 1.5 2009/11/04 15:52:06 steveu Exp $ */ #if !defined(_SPANDSP_PRIVATE_V18_H_) @@ -31,7 +31,7 @@ struct v18_state_s { /*! \brief TRUE if we are the calling modem */ - int caller; + int calling_party; int mode; put_msg_func_t put_msg; void *user_data; diff --git a/libs/spandsp/src/spandsp/private/v22bis.h b/libs/spandsp/src/spandsp/private/v22bis.h index 6a82dcef6e..a2e07d5392 100644 --- a/libs/spandsp/src/spandsp/private/v22bis.h +++ b/libs/spandsp/src/spandsp/private/v22bis.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v22bis.h,v 1.11 2009/07/09 13:52:09 steveu Exp $ + * $Id: v22bis.h,v 1.12 2009/11/04 15:52:06 steveu Exp $ */ #if !defined(_SPANDSP_PRIVATE_V22BIS_H_) @@ -76,7 +76,7 @@ struct v22bis_state_s /*! \brief The maximum permitted bit rate of the modem. Valid values are 1200 and 2400. */ int bit_rate; /*! \brief TRUE is this is the calling side modem. */ - int caller; + int calling_party; /*! \brief The callback function used to get the next bit to be transmitted. */ get_bit_func_t get_bit; /*! \brief A user specified opaque pointer passed to the get_bit callback routine. */ diff --git a/libs/spandsp/src/spandsp/private/v42.h b/libs/spandsp/src/spandsp/private/v42.h index 1dd61119ec..1a1347c746 100644 --- a/libs/spandsp/src/spandsp/private/v42.h +++ b/libs/spandsp/src/spandsp/private/v42.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v42.h,v 1.1 2008/11/15 14:43:08 steveu Exp $ + * $Id: v42.h,v 1.2 2009/11/04 15:52:06 steveu Exp $ */ #if !defined(_SPANDSP_PRIVATE_V42_H_) @@ -92,7 +92,7 @@ struct lapm_state_s struct v42_state_s { /*! TRUE if we are the calling party, otherwise FALSE */ - int caller; + int calling_party; /*! TRUE if we should detect whether the far end is V.42 capable. FALSE if we go directly to protocol establishment */ int detect; diff --git a/libs/spandsp/src/spandsp/private/v8.h b/libs/spandsp/src/spandsp/private/v8.h index b22e6a5cec..80fd599a2f 100644 --- a/libs/spandsp/src/spandsp/private/v8.h +++ b/libs/spandsp/src/spandsp/private/v8.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v8.h,v 1.1 2008/10/13 13:14:01 steveu Exp $ + * $Id: v8.h,v 1.3 2009/11/04 15:52:06 steveu Exp $ */ #if !defined(_SPANDSP_PRIVATE_V8_H_) @@ -31,9 +31,15 @@ struct v8_state_s { /*! \brief TRUE if we are the calling modem */ - int caller; - /*! \brief The current state of the V8 protocol */ + int calling_party; + + v8_result_handler_t *result_handler; + void *result_handler_user_data; + + /*! \brief The current state of the V.8 protocol */ int state; + int fsk_tx_on; + int modem_connect_tone_tx_on; int negotiation_timer; int ci_timer; int ci_count; @@ -43,24 +49,14 @@ struct v8_state_s modem_connect_tones_tx_state_t ansam_tx; modem_connect_tones_rx_state_t ansam_rx; - v8_result_handler_t *result_handler; - void *result_handler_user_data; - /*! \brief Modulation schemes available at this end. */ - int available_modulations; + int local_end_modulations; int common_modulations; - int negotiated_modulation; - int far_end_modulations; - - int call_function; - int protocol; - int pstn_access; - int nsf_seen; - int pcm_modem_availability; - int t66_seen; - /* V8 data parsing */ - unsigned int bit_stream; + v8_result_t result; + + /* V.8 data parsing */ + uint32_t bit_stream; int bit_cnt; /* Indicates the type of message coming up */ int preamble_type; @@ -70,7 +66,7 @@ struct v8_state_s /*! \brief a reference copy of the last CM or JM message, used when testing for matches. */ uint8_t cm_jm_data[64]; - int cm_jm_count; + int cm_jm_len; int got_cm_jm; int got_cj; int zero_byte_count; diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h index d0d71f674d..3c1b441030 100644 --- a/libs/spandsp/src/spandsp/t30.h +++ b/libs/spandsp/src/spandsp/t30.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t30.h,v 1.126 2009/09/21 15:52:39 steveu Exp $ + * $Id: t30.h,v 1.126.4.1 2009/12/19 09:47:56 steveu Exp $ */ /*! \file */ @@ -347,7 +347,7 @@ enum T30_SUPPORT_V17 = 0x04, /*! Support the V.34 modem (up to 33,600bps) for image transfer. */ T30_SUPPORT_V34 = 0x08, - /*! Support the Internet Aware FAX mode (no bit rate limit) for image transfer. */ + /*! Support the Internet aware FAX mode (no bit rate limit) for image transfer. */ T30_SUPPORT_IAF = 0x10 }; @@ -361,16 +361,18 @@ enum T30_SUPPORT_T4_2D_COMPRESSION = 0x04, /*! T.6 2D compression */ T30_SUPPORT_T6_COMPRESSION = 0x08, - /*! T.85 monochrome JBIG coding */ + /*! T.85 monochrome JBIG compression */ T30_SUPPORT_T85_COMPRESSION = 0x10, - /*! T.43 colour JBIG coding */ + /*! T.43 colour JBIG compression */ T30_SUPPORT_T43_COMPRESSION = 0x20, /*! T.45 run length colour compression */ T30_SUPPORT_T45_COMPRESSION = 0x40, - /*! T.81 + T.30 Annex E colour JPEG coding */ + /*! T.81 + T.30 Annex E colour JPEG compression */ T30_SUPPORT_T81_COMPRESSION = 0x80, - /*! T.81 + T.30 Annex K colour sYCC-JPEG coding */ - T30_SUPPORT_SYCC_T81_COMPRESSION = 0x100 + /*! T.81 + T.30 Annex K colour sYCC-JPEG compression */ + T30_SUPPORT_SYCC_T81_COMPRESSION = 0x100, + /*! T.88 monochrome JBIG2 compression */ + T30_SUPPORT_T88_COMPRESSION = 0x200 }; enum diff --git a/libs/spandsp/src/spandsp/t30_fcf.h b/libs/spandsp/src/spandsp/t30_fcf.h index f32d8b7c62..a303fb4f93 100644 --- a/libs/spandsp/src/spandsp/t30_fcf.h +++ b/libs/spandsp/src/spandsp/t30_fcf.h @@ -1,7 +1,7 @@ /* * SpanDSP - a series of DSP components for telephony * - * fcf.h - ITU T.30 fax control field definitions + * t30_fcf.h - ITU T.30 fax control field definitions * * Written by Steve Underwood * @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t30_fcf.h,v 1.17 2008/08/03 03:44:00 steveu Exp $ + * $Id: t30_fcf.h,v 1.18 2009/10/08 15:14:31 steveu Exp $ */ /*! \file */ diff --git a/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h b/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h index a1c6cc2e58..8ffffde18b 100644 --- a/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h +++ b/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h @@ -23,7 +23,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_non_ecm_buffer.h,v 1.7 2009/02/10 13:06:47 steveu Exp $ + * $Id: t38_non_ecm_buffer.h,v 1.7.4.1 2009/12/19 06:43:28 steveu Exp $ */ /*! \file */ @@ -35,9 +35,38 @@ \section t38_non_ecm_buffer_page_sec_1 What does it do? The T.38 rate adapting non-ECM image data buffer is used to buffer TCF and non-ECM -FAX image data being gatewayed from a T.38 linke to an analogue FAX modem link. +FAX image data being gatewayed from a T.38 link to an analogue FAX modem link. + +As well as rate adapting, the buffer has the ability to impose a minimum on the number +of bits per row of image data. This allows any row padding zeros to be stripped from +the data stream, to minimise the data sent as T.38 packets, and be reinserted before +the data is sent to its final destination. Not all T.38 implementations support this +feature, so it's use must be negotiated. \section t38_non_ecm_buffer_page_sec_2 How does it work? + +When inserting padding bits, whether to ensure a minimum row time or for flow control, +it is important the right value is inserted at the right point in the data sequence. +If we are in the optional initial period of all ones, we can insert a byte of extra +ones at any time. Once we pass that initial stage, TCF and image data need separate +handling. + +TCF data is all zeros. Once the period of all zeros has begun it is OK to insert +additional bytes of zeros at any point. + +Image data consists of rows, separated by EOL (end of line) markers. Inserting +zeros at arbitrary times would corrupt the image. However, it is OK to insert a +considerable number of extra zeros just before an EOL. Therefore we track where the +EOL markers occur as we fill the buffer. As we empty the buffer stop outputting real +data, and start outputting bytes of zero, if we reach this last EOL marker location. +The EOL marker is 11 zeros following by 1 (1D mode) or 2 (2D mode) ones. Therefore, it +always spills across 2 bytes in the buffer, and there is always a point where we can +insert our extra zeros between bytes. + +Padding between the group of successive EOL markers which for the RTC (return to control) +marker that ends an image causes some FAX machines not to recognise them as an RTC condition. +Therefore, our padding applies special protection so padding never occurs between two +successive EOL markers, with no pixel data between them. */ /*! The buffer length much be a power of two. The chosen length is big enough for diff --git a/libs/spandsp/src/spandsp/t4_rx.h b/libs/spandsp/src/spandsp/t4_rx.h new file mode 100644 index 0000000000..1cc8873251 --- /dev/null +++ b/libs/spandsp/src/spandsp/t4_rx.h @@ -0,0 +1,344 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * t4_rx.h - definitions for T.4 FAX receive processing + * + * Written by Steve Underwood + * + * Copyright (C) 2003 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: t4_rx.h,v 1.3.2.3 2009/12/21 17:18:40 steveu Exp $ + */ + +/*! \file */ + +#if !defined(_SPANDSP_T4_RX_H_) +#define _SPANDSP_T4_RX_H_ + +/*! \page t4_page T.4 image compression and decompression + +\section t4_page_sec_1 What does it do? +The T.4 image compression and decompression routines implement the 1D and 2D +encoding methods defined in ITU specification T.4. They also implement the pure +2D encoding method defined in T.6. These are image compression algorithms used +for FAX transmission. + +\section t4_page_sec_1 How does it work? +*/ + +typedef int (*t4_row_write_handler_t)(void *user_data, const uint8_t buf[], size_t len); + +/*! Supported compression modes. */ +typedef enum +{ + /*! No compression */ + T4_COMPRESSION_NONE = 0, + /*! T.1 1D compression */ + T4_COMPRESSION_ITU_T4_1D = 1, + /*! T.4 2D compression */ + T4_COMPRESSION_ITU_T4_2D = 2, + /*! T.6 2D compression */ + T4_COMPRESSION_ITU_T6 = 3, + /*! T.85 monochrome JBIG coding */ + T4_COMPRESSION_ITU_T85 = 4, + /*! T.43 colour JBIG coding */ + T4_COMPRESSION_ITU_T43 = 5, + /*! T.45 run length colour compression */ + T4_COMPRESSION_ITU_T45 = 6, + /*! T.81 + T.30 Annex E colour JPEG coding */ + T4_COMPRESSION_ITU_T81 = 7, + /*! T.81 + T.30 Annex K colour sYCC-JPEG coding */ + T4_COMPRESSION_ITU_SYCC_T81 = 8 +} t4_image_compression_t; + +/*! Supported X resolutions, in pixels per metre. */ +typedef enum +{ + T4_X_RESOLUTION_R4 = 4016, + T4_X_RESOLUTION_R8 = 8031, + T4_X_RESOLUTION_300 = 11811, + T4_X_RESOLUTION_R16 = 16063, + T4_X_RESOLUTION_600 = 23622, + T4_X_RESOLUTION_800 = 31496, + T4_X_RESOLUTION_1200 = 47244 +} t4_image_x_resolution_t; + +/*! Supported Y resolutions, in pixels per metre. */ +typedef enum +{ + T4_Y_RESOLUTION_STANDARD = 3850, + T4_Y_RESOLUTION_FINE = 7700, + T4_Y_RESOLUTION_300 = 11811, + T4_Y_RESOLUTION_SUPERFINE = 15400, /* 400 is 15748 */ + T4_Y_RESOLUTION_600 = 23622, + T4_Y_RESOLUTION_800 = 31496, + T4_Y_RESOLUTION_1200 = 47244 +} t4_image_y_resolution_t; + +/*! + Exact widths in PELs for the difference resolutions, and page widths. + Note: + The A4 widths also apply to North American letter and legal. + The R4 resolution widths are not supported in recent versions of T.30 + Only images of exactly these widths are acceptable for FAX transmisson. + + R4 864 pels/215mm for ISO A4, North American Letter and Legal + R4 1024 pels/255mm for ISO B4 + R4 1216 pels/303mm for ISO A3 + R8 1728 pels/215mm for ISO A4, North American Letter and Legal + R8 2048 pels/255mm for ISO B4 + R8 2432 pels/303mm for ISO A3 + R16 3456 pels/215mm for ISO A4, North American Letter and Legal + R16 4096 pels/255mm for ISO B4 + R16 4864 pels/303mm for ISO A3 +*/ +typedef enum +{ + T4_WIDTH_R4_A4 = 864, + T4_WIDTH_R4_B4 = 1024, + T4_WIDTH_R4_A3 = 1216, + T4_WIDTH_R8_A4 = 1728, + T4_WIDTH_R8_B4 = 2048, + T4_WIDTH_R8_A3 = 2432, + T4_WIDTH_300_A4 = 2592, + T4_WIDTH_300_B4 = 3072, + T4_WIDTH_300_A3 = 3648, + T4_WIDTH_R16_A4 = 3456, + T4_WIDTH_R16_B4 = 4096, + T4_WIDTH_R16_A3 = 4864, + T4_WIDTH_600_A4 = 5184, + T4_WIDTH_600_B4 = 6144, + T4_WIDTH_600_A3 = 7296, + T4_WIDTH_1200_A4 = 10368, + T4_WIDTH_1200_B4 = 12288, + T4_WIDTH_1200_A3 = 14592 +} t4_image_width_t; + +/*! + Length of the various supported paper sizes, in pixels at the various Y resolutions. + Paper sizes are + A4 (215mm x 297mm) + B4 (255mm x 364mm) + A3 (303mm x 418.56mm) + North American Letter (215.9mm x 279.4mm) + North American Legal (215.9mm x 355.6mm) + Unlimited + + T.4 does not accurately define the maximum number of scan lines in a page. A wide + variety of maximum row counts are used in the real world. It is important not to + set our sending limit too high, or a receiving machine might split pages. It is + important not to set it too low, or we might clip pages. + + Values seen for standard resolution A4 pages include 1037, 1045, 1109, 1126 and 1143. + 1109 seems the most-popular. At fine res 2150, 2196, 2200, 2237, 2252-2262, 2264, + 2286, and 2394 are used. 2255 seems the most popular. We try to use balanced choices + here. +*/ +typedef enum +{ + /* A4 is 297mm long */ + T4_LENGTH_STANDARD_A4 = 1143, + T4_LENGTH_FINE_A4 = 2286, + T4_LENGTH_300_A4 = 4665, + T4_LENGTH_SUPERFINE_A4 = 4573, + T4_LENGTH_600_A4 = 6998, + T4_LENGTH_800_A4 = 9330, + T4_LENGTH_1200_A4 = 13996, + /* B4 is 364mm long */ + T4_LENGTH_STANDARD_B4 = 1401, + T4_LENGTH_FINE_B4 = 2802, + T4_LENGTH_300_B4 = 0, + T4_LENGTH_SUPERFINE_B4 = 5605, + T4_LENGTH_600_B4 = 0, + T4_LENGTH_800_B4 = 0, + T4_LENGTH_1200_B4 = 0, + /* North American letter is 279.4mm long */ + T4_LENGTH_STANDARD_US_LETTER = 1075, + T4_LENGTH_FINE_US_LETTER = 2151, + T4_LENGTH_300_US_LETTER = 0, + T4_LENGTH_SUPERFINE_US_LETTER = 4302, + T4_LENGTH_600_US_LETTER = 0, + T4_LENGTH_800_US_LETTER = 0, + T4_LENGTH_1200_US_LETTER = 0, + /* North American legal is 355.6mm long */ + T4_LENGTH_STANDARD_US_LEGAL = 1369, + T4_LENGTH_FINE_US_LEGAL = 2738, + T4_LENGTH_300_US_LEGAL = 0, + T4_LENGTH_SUPERFINE_US_LEGAL = 5476, + T4_LENGTH_600_US_LEGAL = 0, + T4_LENGTH_800_US_LEGAL = 0, + T4_LENGTH_1200_US_LEGAL = 0 +} t4_image_length_t; + +/*! + T.4 FAX compression/decompression descriptor. This defines the working state + for a single instance of a T.4 FAX compression or decompression channel. +*/ +typedef struct t4_state_s t4_state_t; + +/*! + T.4 FAX compression/decompression statistics. +*/ +typedef struct +{ + /*! \brief The number of pages transferred so far. */ + int pages_transferred; + /*! \brief The number of pages in the file (<0 if unknown). */ + int pages_in_file; + /*! \brief The number of horizontal pixels in the most recent page. */ + int width; + /*! \brief The number of vertical pixels in the most recent page. */ + int length; + /*! \brief The number of bad pixel rows in the most recent page. */ + int bad_rows; + /*! \brief The largest number of bad pixel rows in a block in the most recent page. */ + int longest_bad_row_run; + /*! \brief The horizontal resolution of the page in pixels per metre */ + int x_resolution; + /*! \brief The vertical resolution of the page in pixels per metre */ + int y_resolution; + /*! \brief The type of compression used between the FAX machines */ + int encoding; + /*! \brief The size of the image on the line, in bytes */ + int line_image_size; +} t4_stats_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! \brief Prepare for reception of a document. + \param s The T.4 context. + \param file The name of the file to be received. + \param output_encoding The output encoding. + \return A pointer to the context, or NULL if there was a problem. */ +SPAN_DECLARE(t4_state_t *) t4_rx_init(t4_state_t *s, const char *file, int output_encoding); + +/*! \brief Prepare to receive the next page of the current document. + \param s The T.4 context. + \return zero for success, -1 for failure. */ +SPAN_DECLARE(int) t4_rx_start_page(t4_state_t *s); + +/*! \brief Put a bit of the current document page. + \param s The T.4 context. + \param bit The data bit. + \return TRUE when the bit ends the document page, otherwise FALSE. */ +SPAN_DECLARE(int) t4_rx_put_bit(t4_state_t *s, int bit); + +/*! \brief Put a byte of the current document page. + \param s The T.4 context. + \param byte The data byte. + \return TRUE when the byte ends the document page, otherwise FALSE. */ +SPAN_DECLARE(int) t4_rx_put_byte(t4_state_t *s, uint8_t byte); + +/*! \brief Put a byte of the current document page. + \param s The T.4 context. + \param buf The buffer containing the chunk. + \param len The length of the chunk. + \return TRUE when the byte ends the document page, otherwise FALSE. */ +SPAN_DECLARE(int) t4_rx_put_chunk(t4_state_t *s, const uint8_t buf[], int len); + +/*! \brief Complete the reception of a page. + \param s The T.4 receive context. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_rx_end_page(t4_state_t *s); + +/*! \brief End reception of a document. Tidy up and close the file. + This should be used to end T.4 reception started with + t4_rx_init. + \param s The T.4 receive context. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_rx_release(t4_state_t *s); + +/*! \brief End reception of a document. Tidy up, close the file and + free the context. This should be used to end T.4 reception + started with t4_rx_init. + \param s The T.4 receive context. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_rx_free(t4_state_t *s); + +/*! \brief Set the row write handler for a T.4 receive context. + \param s The T.4 receive context. + \param handler A pointer to the handler routine. + \param user_data An opaque pointer passed to the handler routine. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_state_t *s, t4_row_write_handler_t handler, void *user_data); + +/*! \brief Set the encoding for the received data. + \param s The T.4 context. + \param encoding The encoding. */ +SPAN_DECLARE(void) t4_rx_set_rx_encoding(t4_state_t *s, int encoding); + +/*! \brief Set the expected width of the received image, in pixel columns. + \param s The T.4 context. + \param width The number of pixels across the image. */ +SPAN_DECLARE(void) t4_rx_set_image_width(t4_state_t *s, int width); + +/*! \brief Set the row-to-row (y) resolution to expect for a received image. + \param s The T.4 context. + \param resolution The resolution, in pixels per metre. */ +SPAN_DECLARE(void) t4_rx_set_y_resolution(t4_state_t *s, int resolution); + +/*! \brief Set the column-to-column (x) resolution to expect for a received image. + \param s The T.4 context. + \param resolution The resolution, in pixels per metre. */ +SPAN_DECLARE(void) t4_rx_set_x_resolution(t4_state_t *s, int resolution); + +/*! \brief Set the DCS information of the fax, for inclusion in the file. + \param s The T.4 context. + \param dcs The DCS information, formatted as an ASCII string. */ +SPAN_DECLARE(void) t4_rx_set_dcs(t4_state_t *s, const char *dcs); + +/*! \brief Set the sub-address of the fax, for inclusion in the file. + \param s The T.4 context. + \param sub_address The sub-address string. */ +SPAN_DECLARE(void) t4_rx_set_sub_address(t4_state_t *s, const char *sub_address); + +/*! \brief Set the identity of the remote machine, for inclusion in the file. + \param s The T.4 context. + \param ident The identity string. */ +SPAN_DECLARE(void) t4_rx_set_far_ident(t4_state_t *s, const char *ident); + +/*! \brief Set the vendor of the remote machine, for inclusion in the file. + \param s The T.4 context. + \param vendor The vendor string, or NULL. */ +SPAN_DECLARE(void) t4_rx_set_vendor(t4_state_t *s, const char *vendor); + +/*! \brief Set the model of the remote machine, for inclusion in the file. + \param s The T.4 context. + \param model The model string, or NULL. */ +SPAN_DECLARE(void) t4_rx_set_model(t4_state_t *s, const char *model); + +/*! Get the current image transfer statistics. + \brief Get the current transfer statistics. + \param s The T.4 context. + \param t A pointer to a statistics structure. */ +SPAN_DECLARE(void) t4_get_transfer_statistics(t4_state_t *s, t4_stats_t *t); + +/*! Get the short text name of an encoding format. + \brief Get the short text name of an encoding format. + \param encoding The encoding type. + \return A pointer to the string. */ +SPAN_DECLARE(const char *) t4_encoding_to_str(int encoding); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t4_tx.h b/libs/spandsp/src/spandsp/t4_tx.h new file mode 100644 index 0000000000..c30386c03d --- /dev/null +++ b/libs/spandsp/src/spandsp/t4_tx.h @@ -0,0 +1,179 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * t4_tx.h - definitions for T.4 FAX transmit processing + * + * Written by Steve Underwood + * + * Copyright (C) 2003 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: t4_tx.h,v 1.2.2.3 2009/12/21 17:18:40 steveu Exp $ + */ + +/*! \file */ + +#if !defined(_SPANDSP_T4_TX_H_) +#define _SPANDSP_T4_TX_H_ + +typedef int (*t4_row_read_handler_t)(void *user_data, uint8_t buf[], size_t len); + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! \brief Prepare for transmission of a document. + \param s The T.4 context. + \param file The name of the file to be sent. + \param start_page The first page to send. -1 for no restriction. + \param stop_page The last page to send. -1 for no restriction. + \return A pointer to the context, or NULL if there was a problem. */ +SPAN_DECLARE(t4_state_t *) t4_tx_init(t4_state_t *s, const char *file, int start_page, int stop_page); + +/*! \brief Prepare to send the next page of the current document. + \param s The T.4 context. + \return zero for success, -1 for failure. */ +SPAN_DECLARE(int) t4_tx_start_page(t4_state_t *s); + +/*! \brief Prepare the current page for a resend. + \param s The T.4 context. + \return zero for success, -1 for failure. */ +SPAN_DECLARE(int) t4_tx_restart_page(t4_state_t *s); + +/*! \brief Check for the existance of the next page, and whether its format is like the + current one. This information can be needed before it is determined that the current + page is finished with. + \param s The T.4 context. + \return 0 for next page found with the same format as the current page. + 1 for next page found with different format from the current page. + -1 for no page found, or file failure. */ +SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_state_t *s); + +/*! \brief Complete the sending of a page. + \param s The T.4 context. + \return zero for success, -1 for failure. */ +SPAN_DECLARE(int) t4_tx_end_page(t4_state_t *s); + +/*! \brief Return the next bit of the current document page, without actually + moving forward in the buffer. The document will be padded for the + current minimum scan line time. + \param s The T.4 context. + \return The next bit (i.e. 0 or 1). For the last bit of data, bit 1 is + set (i.e. the returned value is 2 or 3). */ +SPAN_DECLARE(int) t4_tx_check_bit(t4_state_t *s); + +/*! \brief Get the next bit of the current document page. The document will + be padded for the current minimum scan line time. + \param s The T.4 context. + \return The next bit (i.e. 0 or 1). For the last bit of data, bit 1 is + set (i.e. the returned value is 2 or 3). */ +SPAN_DECLARE(int) t4_tx_get_bit(t4_state_t *s); + +/*! \brief Get the next byte of the current document page. The document will + be padded for the current minimum scan line time. + \param s The T.4 context. + \return The next byte. For the last byte of data, bit 8 is + set. In this case, one or more bits of the byte may be padded with + zeros, to complete the byte. */ +SPAN_DECLARE(int) t4_tx_get_byte(t4_state_t *s); + +/*! \brief Get the next chunk of the current document page. The document will + be padded for the current minimum scan line time. + \param s The T.4 context. + \param buf The buffer into which the chunk is to written. + \param max_len The maximum length of the chunk. + \return The actual length of the chunk. If this is less than max_len it + indicates that the end of the document has been reached. */ +SPAN_DECLARE(int) t4_tx_get_chunk(t4_state_t *s, uint8_t buf[], int max_len); + +/*! \brief End the transmission of a document. Tidy up and close the file. + This should be used to end T.4 transmission started with t4_tx_init. + \param s The T.4 context. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_tx_release(t4_state_t *s); + +/*! \brief End the transmission of a document. Tidy up, close the file and + free the context. This should be used to end T.4 transmission + started with t4_tx_init. + \param s The T.4 context. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_tx_free(t4_state_t *s); + +/*! \brief Set the encoding for the encoded data. + \param s The T.4 context. + \param encoding The encoding. */ +SPAN_DECLARE(void) t4_tx_set_tx_encoding(t4_state_t *s, int encoding); + +/*! \brief Set the minimum number of encoded bits per row. This allows the + makes the encoding process to be set to comply with the minimum row + time specified by a remote receiving machine. + \param s The T.4 context. + \param bits The minimum number of bits per row. */ +SPAN_DECLARE(void) t4_tx_set_min_row_bits(t4_state_t *s, int bits); + +/*! \brief Set the identity of the local machine, for inclusion in page headers. + \param s The T.4 context. + \param ident The identity string. */ +SPAN_DECLARE(void) t4_tx_set_local_ident(t4_state_t *s, const char *ident); + +/*! Set the info field, included in the header line included in each page of an encoded + FAX. This is a string of up to 50 characters. Other information (date, local ident, etc.) + are automatically included in the header. If the header info is set to NULL or a zero + length string, no header lines will be added to the encoded FAX. + \brief Set the header info. + \param s The T.4 context. + \param info A string, of up to 50 bytes, which will form the info field. */ +SPAN_DECLARE(void) t4_tx_set_header_info(t4_state_t *s, const char *info); + +/*! \brief Set the row read handler for a T.4 transmit context. + \param s The T.4 transmit context. + \param handler A pointer to the handler routine. + \param user_data An opaque pointer passed to the handler routine. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_state_t *s, t4_row_read_handler_t handler, void *user_data); + +/*! \brief Get the row-to-row (y) resolution of the current page. + \param s The T.4 context. + \return The resolution, in pixels per metre. */ +SPAN_DECLARE(int) t4_tx_get_y_resolution(t4_state_t *s); + +/*! \brief Get the column-to-column (x) resolution of the current page. + \param s The T.4 context. + \return The resolution, in pixels per metre. */ +SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_state_t *s); + +/*! \brief Get the width of the current page, in pixel columns. + \param s The T.4 context. + \return The number of columns. */ +SPAN_DECLARE(int) t4_tx_get_image_width(t4_state_t *s); + +/*! \brief Get the number of pages in the file. + \param s The T.4 context. + \return The number of pages, or -1 if there is an error. */ +SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_state_t *s); + +/*! \brief Get the currnet page number in the file. + \param s The T.4 context. + \return The page number, or -1 if there is an error. */ +SPAN_DECLARE(int) t4_tx_get_current_page_in_file(t4_state_t *s); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/telephony.h b/libs/spandsp/src/spandsp/telephony.h index 3f39309faa..703c0bd966 100644 --- a/libs/spandsp/src/spandsp/telephony.h +++ b/libs/spandsp/src/spandsp/telephony.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: telephony.h,v 1.18 2009/03/23 14:17:42 steveu Exp $ + * $Id: telephony.h,v 1.18.4.2 2009/12/21 18:38:06 steveu Exp $ */ #if !defined(_SPANDSP_TELEPHONY_H_) @@ -69,8 +69,8 @@ typedef int (span_rx_fillin_handler_t)(void *s, int len); /*! \brief A handler for transmit, where the buffer will be filled. */ typedef int (span_tx_handler_t)(void *s, int16_t amp[], int max_len); -#define ms_to_samples(t) (((t)*SAMPLE_RATE)/1000) -#define us_to_samples(t) (((t)*SAMPLE_RATE)/1000000) +#define ms_to_samples(t) ((t)*(SAMPLE_RATE/1000)) +#define us_to_samples(t) ((t)/(1000000/SAMPLE_RATE)) #if !defined(FALSE) #define FALSE 0 diff --git a/libs/spandsp/src/spandsp/v18.h b/libs/spandsp/src/spandsp/v18.h index 506553b488..7e964cdba6 100644 --- a/libs/spandsp/src/spandsp/v18.h +++ b/libs/spandsp/src/spandsp/v18.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v18.h,v 1.5 2009/06/02 16:03:56 steveu Exp $ + * $Id: v18.h,v 1.6 2009/11/04 15:52:06 steveu Exp $ */ /*! \file */ @@ -69,14 +69,14 @@ SPAN_DECLARE(logging_state_t *) v18_get_logging_state(v18_state_t *s); /*! Initialise a V.18 context. \brief Initialise a V.18 context. \param s The V.18 context. - \param caller TRUE if caller mode, else answerer mode. + \param calling_party TRUE if caller mode, else answerer mode. \param mode Mode of operation. \param put_msg A callback routine called to deliver the received text to the application. \param user_data An opaque pointer for the callback routine. \return A pointer to the V.18 context, or NULL if there was a problem. */ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, - int caller, + int calling_party, int mode, put_msg_func_t put_msg, void *user_data); diff --git a/libs/spandsp/src/spandsp/v22bis.h b/libs/spandsp/src/spandsp/v22bis.h index 237f5baf81..aa2a50a05d 100644 --- a/libs/spandsp/src/spandsp/v22bis.h +++ b/libs/spandsp/src/spandsp/v22bis.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v22bis.h,v 1.45 2009/07/09 13:52:09 steveu Exp $ + * $Id: v22bis.h,v 1.46 2009/11/04 15:52:06 steveu Exp $ */ /*! \file */ @@ -164,7 +164,7 @@ SPAN_DECLARE(int) v22bis_current_bit_rate(v22bis_state_t *s); \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 1200 and 2400. \param guard The guard tone option. 0 = none, 1 = 550Hz, 2 = 1800Hz. - \param caller TRUE if this is the calling modem. + \param calling_party TRUE if this is the calling modem. \param get_bit The callback routine used to get the data to be transmitted. \param put_bit The callback routine used to get the data to be transmitted. \param user_data An opaque pointer, passed in calls to the get and put routines. @@ -172,7 +172,7 @@ SPAN_DECLARE(int) v22bis_current_bit_rate(v22bis_state_t *s); SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s, int bit_rate, int guard, - int caller, + int calling_party, get_bit_func_t get_bit, void *get_bit_user_data, put_bit_func_t put_bit, diff --git a/libs/spandsp/src/spandsp/v42.h b/libs/spandsp/src/spandsp/v42.h index 3185908d04..bba70af5be 100644 --- a/libs/spandsp/src/spandsp/v42.h +++ b/libs/spandsp/src/spandsp/v42.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v42.h,v 1.30 2009/02/10 13:06:47 steveu Exp $ + * $Id: v42.h,v 1.31 2009/11/04 15:52:06 steveu Exp $ */ /*! \page v42_page V.42 modem error correction @@ -130,12 +130,12 @@ SPAN_DECLARE(int) v42_tx_bit(void *user_data); /*! Initialise a V.42 context. \param s The V.42 context. - \param caller TRUE if caller mode, else answerer mode. + \param calling_party TRUE if caller mode, else answerer mode. \param frame_handler A callback function to handle received frames of data. \param user_data An opaque pointer passed to the frame handler routine. \return ??? */ -SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int caller, int detect, v42_frame_handler_t frame_handler, void *user_data); +SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int calling_party, int detect, v42_frame_handler_t frame_handler, void *user_data); /*! Restart a V.42 context. \param s The V.42 context. diff --git a/libs/spandsp/src/spandsp/v8.h b/libs/spandsp/src/spandsp/v8.h index d4d3db2da5..0bfdf87c5a 100644 --- a/libs/spandsp/src/spandsp/v8.h +++ b/libs/spandsp/src/spandsp/v8.h @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v8.h,v 1.28 2009/06/02 16:03:56 steveu Exp $ + * $Id: v8.h,v 1.31 2009/11/04 16:10:14 steveu Exp $ */ /*! \file */ @@ -50,13 +50,13 @@ typedef void (v8_result_handler_t)(void *user_data, v8_result_t *result); enum v8_call_function_e { V8_CALL_TBS = 0, - V8_CALL_H324, - V8_CALL_V18, - V8_CALL_T101, - V8_CALL_T30_TX, - V8_CALL_T30_RX, - V8_CALL_V_SERIES, - V8_CALL_FUNCTION_EXTENSION + V8_CALL_H324 = 1, + V8_CALL_V18 = 2, + V8_CALL_T101 = 3, + V8_CALL_T30_TX = 4, + V8_CALL_T30_RX = 5, + V8_CALL_V_SERIES = 6, + V8_CALL_FUNCTION_EXTENSION = 7 }; enum v8_modulation_e @@ -88,30 +88,33 @@ enum v8_protocol_e enum v8_pstn_access_e { - V8_PSTN_ACCESS_CALL_DCE_CELLULAR = 0x20, - V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR = 0x40, - V8_PSTN_ACCESS_DCE_ON_DIGTIAL = 0x80 + V8_PSTN_ACCESS_CALL_DCE_CELLULAR = 0x01, + V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR = 0x02, + V8_PSTN_ACCESS_DCE_ON_DIGITAL = 0x04 }; enum v8_pcm_modem_availability_e { - V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE = 0x20, - V8_PSTN_PCM_MODEM_V90_V92_DIGITAL = 0x40, - V8_PSTN_PCM_MODEM_V91 = 0x80 + V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE = 0x01, + V8_PSTN_PCM_MODEM_V90_V92_DIGITAL = 0x02, + V8_PSTN_PCM_MODEM_V91 = 0x04 }; typedef struct v8_state_s v8_state_t; struct v8_result_s { + int modem_connect_tone_detected; int call_function; - int available_modulations; + int far_end_modulations; int negotiated_modulation; int protocol; int pstn_access; int nsf_seen; + int nsf; int pcm_modem_availability; int t66_seen; + int t66; }; #if defined(__cplusplus) @@ -122,14 +125,16 @@ extern "C" /*! Initialise a V.8 context. \brief Initialise a V.8 context. \param s The V.8 context. - \param caller TRUE if caller mode, else answerer mode. + \param calling_party TRUE if caller mode, else answerer mode. + \param use_ansam_pr TRUE if ANSam/ is to be used, else ANSam will be used. \param available_modulations A bitwise list of the modulation schemes to be advertised as available here. \param result_handler The callback routine used to handle the results of negotiation. \param user_data An opaque pointer passed to the result_handler routine. \return A pointer to the V.8 context, or NULL if there was a problem. */ SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s, - int caller, + int calling_party, + int use_ansam_pr, int available_modulations, v8_result_handler_t *result_handler, void *user_data); @@ -175,7 +180,9 @@ SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function); SPAN_DECLARE(const char *) v8_modulation_to_str(int modulation_scheme); SPAN_DECLARE(const char *) v8_protocol_to_str(int protocol); SPAN_DECLARE(const char *) v8_pstn_access_to_str(int pstn_access); +SPAN_DECLARE(const char *) v8_nsf_to_str(int nsf); SPAN_DECLARE(const char *) v8_pcm_modem_availability_to_str(int pcm_modem_availability); +SPAN_DECLARE(const char *) v8_t66_to_str(int t66); #if defined(__cplusplus) } diff --git a/libs/spandsp/src/spandsp/version.h b/libs/spandsp/src/spandsp/version.h index 1060929860..99a624ea40 100644 --- a/libs/spandsp/src/spandsp/version.h +++ b/libs/spandsp/src/spandsp/version.h @@ -10,19 +10,19 @@ * All rights reserved. * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: version.h.in,v 1.3 2009/03/01 12:39:02 steveu Exp $ + * $Id: version.h.in,v 1.3.4.1 2009/12/19 09:47:56 steveu Exp $ */ #if !defined(_SPANDSP_VERSION_H_) @@ -30,9 +30,9 @@ /* The date and time of the version are in UTC form. */ -#define SPANDSP_RELEASE_DATE 20091005 -#define SPANDSP_RELEASE_TIME 163835 -#define SPANDSP_RELEASE_DATETIME_STRING "20091005 163835" +#define SPANDSP_RELEASE_DATE 20091221 +#define SPANDSP_RELEASE_TIME 183911 +#define SPANDSP_RELEASE_DATETIME_STRING "20091221 183911" #endif /*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/version.h.in b/libs/spandsp/src/spandsp/version.h.in index e83b593ef3..8a547f1e13 100644 --- a/libs/spandsp/src/spandsp/version.h.in +++ b/libs/spandsp/src/spandsp/version.h.in @@ -10,19 +10,19 @@ * All rights reserved. * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: version.h.in,v 1.3 2009/03/01 12:39:02 steveu Exp $ + * $Id: version.h.in,v 1.3.4.1 2009/12/19 09:47:56 steveu Exp $ */ #if !defined(_SPANDSP_VERSION_H_) diff --git a/libs/spandsp/src/super_tone_rx.c b/libs/spandsp/src/super_tone_rx.c index 5c9af718d1..8822577de6 100644 --- a/libs/spandsp/src/super_tone_rx.c +++ b/libs/spandsp/src/super_tone_rx.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: super_tone_rx.c,v 1.33 2009/02/10 13:06:46 steveu Exp $ + * $Id: super_tone_rx.c,v 1.33.4.1 2009/12/19 09:47:56 steveu Exp $ */ /*! \file */ @@ -218,8 +218,23 @@ SPAN_DECLARE(super_tone_rx_descriptor_t *) super_tone_rx_make_descriptor(super_t SPAN_DECLARE(int) super_tone_rx_free_descriptor(super_tone_rx_descriptor_t *desc) { + int i; + if (desc) + { + for (i = 0; i < desc->tones; i++) + { + if (desc->tone_list[i]) + free(desc->tone_list[i]); + } + if (desc->tone_list) + free(desc->tone_list); + if (desc->tone_segs) + free(desc->tone_segs); + if (desc->desc) + free(desc->desc); free(desc); + } return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index a112dd9fac..2be5699834 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t30.c,v 1.303 2009/09/21 15:51:18 steveu Exp $ + * $Id: t30.c,v 1.305.4.3 2009/12/19 14:18:12 steveu Exp $ */ /*! \file */ @@ -60,7 +60,8 @@ #include "spandsp/v29tx.h" #include "spandsp/v27ter_rx.h" #include "spandsp/v27ter_tx.h" -#include "spandsp/t4.h" +#include "spandsp/t4_rx.h" +#include "spandsp/t4_tx.h" #include "spandsp/t30_fcf.h" #include "spandsp/t35.h" #include "spandsp/t30.h" @@ -68,8 +69,10 @@ #include "spandsp/t30_logging.h" #include "spandsp/private/logging.h" -#include "spandsp/private/t4.h" +#include "spandsp/private/t4_rx.h" +#include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" +#include "spandsp/private/t30_dis_dtc_dcs_bits.h" #include "t30_local.h" @@ -215,108 +218,108 @@ enum /* All timers specified in milliseconds */ /*! Time-out T0 defines the amount of time an automatic calling terminal waits for the called terminal -to answer the call. -T0 begins after the dialling of the number is completed and is reset: -a) when T0 times out; or -b) when timer T1 is started; or -c) if the terminal is capable of detecting any condition which indicates that the call will not be - successful, when such a condition is detected. -The recommended value of T0 is 60+-5s. However, when it is anticipated that a long call set-up -time may be encountered, an alternative value of up to 120s may be used. -NOTE - National regulations may require the use of other values for T0. */ + to answer the call. + T0 begins after the dialling of the number is completed and is reset: + a) when T0 times out; or + b) when timer T1 is started; or + c) if the terminal is capable of detecting any condition which indicates that the call will not be + successful, when such a condition is detected. + The recommended value of T0 is 60+-5s. However, when it is anticipated that a long call set-up + time may be encountered, an alternative value of up to 120s may be used. + NOTE - National regulations may require the use of other values for T0. */ #define DEFAULT_TIMER_T0 60000 /*! Time-out T1 defines the amount of time two terminals will continue to attempt to identify each -other. T1 is 35+-5s, begins upon entering phase B, and is reset upon detecting a valid signal or -when T1 times out. -For operating methods 3 and 4 (see 3.1), the calling terminal starts time-out T1 upon reception of -the V.21 modulation scheme. -For operating method 4 bis a (see 3.1), the calling terminal starts time-out T1 upon starting -transmission using the V.21 modulation scheme. -Annex A says T1 is also the timeout to be used for the receipt of the first HDLC frame after the -start of high speed flags in ECM mode. This seems a strange reuse of the T1 name, so we distinguish -it here by calling it T1A. */ + other. T1 is 35+-5s, begins upon entering phase B, and is reset upon detecting a valid signal or + when T1 times out. + For operating methods 3 and 4 (see 3.1), the calling terminal starts time-out T1 upon reception of + the V.21 modulation scheme. + For operating method 4 bis a (see 3.1), the calling terminal starts time-out T1 upon starting + transmission using the V.21 modulation scheme. + Annex A says T1 is also the timeout to be used for the receipt of the first HDLC frame after the + start of high speed flags in ECM mode. This seems a strange reuse of the T1 name, so we distinguish + it here by calling it T1A. */ #define DEFAULT_TIMER_T1 35000 #define DEFAULT_TIMER_T1A 35000 /*! Time-out T2 makes use of the tight control between commands and responses to detect the loss of -command/response synchronization. T2 is 6+-1s, and begins when initiating a command search -(e.g., the first entrance into the "command received" subroutine, reference flow diagram in section 5.2). -T2 is reset when an HDLC flag is received or when T2 times out. */ + command/response synchronization. T2 is 6+-1s, and begins when initiating a command search + (e.g., the first entrance into the "command received" subroutine, reference flow diagram in section 5.2). + T2 is reset when an HDLC flag is received or when T2 times out. */ #define DEFAULT_TIMER_T2 7000 /*! Once HDLC flags begin, T2 is reset, and a 3s timer begins. This timer is unnamed in T.30. Here we -term it T2A. No tolerance is specified for this timer. T2A specifies the maximum time to wait for the -end of a frame, after the initial flag has been seen. */ + term it T2A. No tolerance is specified for this timer. T2A specifies the maximum time to wait for the + end of a frame, after the initial flag has been seen. */ #define DEFAULT_TIMER_T2A 3000 /*! If the HDLC carrier falls during reception, we need to apply a minimum time before continuing. If we - don't, there are circumstances where we could continue and reply before the incoming signals have - really finished. E.g. if a bad DCS is received in a DCS-TCF sequence, we need wait for the TCF - carrier to pass, before continuing. This timer is specified as 200ms, but no tolerance is specified. - It is unnamed in T.30. Here we term it T2B */ + don't, there are circumstances where we could continue and reply before the incoming signals have + really finished. E.g. if a bad DCS is received in a DCS-TCF sequence, we need wait for the TCF + carrier to pass, before continuing. This timer is specified as 200ms, but no tolerance is specified. + It is unnamed in T.30. Here we term it T2B */ #define DEFAULT_TIMER_T2B 200 /*! Time-out T3 defines the amount of time a terminal will attempt to alert the local operator in -response to a procedural interrupt. Failing to achieve operator intervention, the terminal will -discontinue this attempt and shall issue other commands or responses. T3 is 10+-5s, begins on the -first detection of a procedural interrupt command/response signal (i.e., PIN/PIP or PRI-Q) and is -reset when T3 times out or when the operator initiates a line request. */ + response to a procedural interrupt. Failing to achieve operator intervention, the terminal will + discontinue this attempt and shall issue other commands or responses. T3 is 10+-5s, begins on the + first detection of a procedural interrupt command/response signal (i.e., PIN/PIP or PRI-Q) and is + reset when T3 times out or when the operator initiates a line request. */ #define DEFAULT_TIMER_T3 15000 /*! Time-out T4 defines the amount of time a terminal will wait for flags to begin, when waiting for a -response from a remote terminal. T2 is 3s +-15%, and begins when initiating a response search -(e.g., the first entrance into the "response received" subroutine, reference flow diagram in section 5.2). -T4 is reset when an HDLC flag is received or when T4 times out. -NOTE - For manual FAX units, the value of timer T4 may be either 3.0s +-15% or 4.5s +-15%. -If the value of 4.5s is used, then after detection of a valid response to the first DIS, it may -be reduced to 3.0s +-15%. T4 = 3.0s +-15% for automatic units. */ + response from a remote terminal. T2 is 3s +-15%, and begins when initiating a response search + (e.g., the first entrance into the "response received" subroutine, reference flow diagram in section 5.2). + T4 is reset when an HDLC flag is received or when T4 times out. + NOTE - For manual FAX units, the value of timer T4 may be either 3.0s +-15% or 4.5s +-15%. + If the value of 4.5s is used, then after detection of a valid response to the first DIS, it may + be reduced to 3.0s +-15%. T4 = 3.0s +-15% for automatic units. */ #define DEFAULT_TIMER_T4 3450 /*! Once HDLC flags begin, T4 is reset, and a 3s timer begins. This timer is unnamed in T.30. Here we -term it T4A. No tolerance is specified for this timer. T4A specifies the maximum time to wait for the -end of a frame, after the initial flag has been seen. Note that a different timer is used for the fast -HDLC in ECM mode, to provide time for physical paper handling. */ + term it T4A. No tolerance is specified for this timer. T4A specifies the maximum time to wait for the + end of a frame, after the initial flag has been seen. Note that a different timer is used for the fast + HDLC in ECM mode, to provide time for physical paper handling. */ #define DEFAULT_TIMER_T4A 3000 /*! If the HDLC carrier falls during reception, we need to apply a minimum time before continuing. if we - don't, there are circumstances where we could continue and reply before the incoming signals have - really finished. E.g. if a bad DCS is received in a DCS-TCF sequence, we need wait for the TCF - carrier to pass, before continuing. This timer is specified as 200ms, but no tolerance is specified. - It is unnamed in T.30. Here we term it T4B */ + don't, there are circumstances where we could continue and reply before the incoming signals have + really finished. E.g. if a bad DCS is received in a DCS-TCF sequence, we need wait for the TCF + carrier to pass, before continuing. This timer is specified as 200ms, but no tolerance is specified. + It is unnamed in T.30. Here we term it T4B */ #define DEFAULT_TIMER_T4B 200 /*! Time-out T5 is defined for the optional T.4 error correction mode. Time-out T5 defines the amount -of time waiting for clearance of the busy condition of the receiving terminal. T5 is 60+-5s and -begins on the first detection of the RNR response. T5 is reset when T5 times out or the MCF or PIP -response is received or when the ERR or PIN response is received in the flow control process after -transmitting the EOR command. If the timer T5 has expired, the DCN command is transmitted for -call release. */ + of time waiting for clearance of the busy condition of the receiving terminal. T5 is 60+-5s and + begins on the first detection of the RNR response. T5 is reset when T5 times out or the MCF or PIP + response is received or when the ERR or PIN response is received in the flow control process after + transmitting the EOR command. If the timer T5 has expired, the DCN command is transmitted for + call release. */ #define DEFAULT_TIMER_T5 65000 /*! (Annex C - ISDN) Time-out T6 defines the amount of time two terminals will continue to attempt to -identify each other. T6 is 5+-0.5s. The timeout begins upon entering Phase B, and is reset upon -detecting a valid signal, or when T6 times out. */ + identify each other. T6 is 5+-0.5s. The timeout begins upon entering Phase B, and is reset upon + detecting a valid signal, or when T6 times out. */ #define DEFAULT_TIMER_T6 5000 /*! (Annex C - ISDN) Time-out T7 is used to detect loss of command/response synchronization. T7 is 6+-1s. -The timeout begins when initiating a command search (e.g., the first entrance into the "command received" -subroutine - see flow diagram in C.5) and is reset upon detecting a valid signal or when T7 times out. */ + The timeout begins when initiating a command search (e.g., the first entrance into the "command received" + subroutine - see flow diagram in C.5) and is reset upon detecting a valid signal or when T7 times out. */ #define DEFAULT_TIMER_T7 7000 /*! (Annex C - ISDN) Time-out T8 defines the amount of time waiting for clearance of the busy condition -of the receiving terminal. T8 is 10+-1s. The timeout begins on the first detection of the combination -of no outstanding corrections and the RNR response. T8 is reset when T8 times out or MCF response is -received. If the timer T8 expires, a DCN command is transmitted for call release. */ + of the receiving terminal. T8 is 10+-1s. The timeout begins on the first detection of the combination + of no outstanding corrections and the RNR response. T8 is reset when T8 times out or MCF response is + received. If the timer T8 expires, a DCN command is transmitted for call release. */ #define DEFAULT_TIMER_T8 10000 /*! Final time we allow for things to flush through the system, before we disconnect, in milliseconds. - 200ms should be fine for a PSTN call. For a T.38 call something longer is desirable. */ + 200ms should be fine for a PSTN call. For a T.38 call something longer is desirable. */ #define FINAL_FLUSH_TIME 1000 /*! The number of PPRs received before CTC or EOR is sent in ECM mode. T.30 defines this as 4, - but it could be varied, and the Japanese spec, for example, does make this value a - variable. */ + but it could be varied, and the Japanese spec, for example, does make this value a + variable. */ #define PPR_LIMIT_BEFORE_CTC_OR_EOR 4 /* HDLC message header byte values */ @@ -401,10 +404,10 @@ static int terminate_operation_in_progress(t30_state_t *s) switch (s->operation_in_progress) { case OPERATION_IN_PROGRESS_T4_TX: - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); break; case OPERATION_IN_PROGRESS_T4_RX: - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); break; } s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; @@ -414,7 +417,7 @@ static int terminate_operation_in_progress(t30_state_t *s) static int tx_start_page(t30_state_t *s) { - if (t4_tx_start_page(&(s->t4))) + if (t4_tx_start_page(&s->t4)) { terminate_operation_in_progress(s); return -1; @@ -429,7 +432,7 @@ static int tx_start_page(t30_state_t *s) static int tx_end_page(t30_state_t *s) { s->retries = 0; - if (t4_tx_end_page(&(s->t4)) == 0) + if (t4_tx_end_page(&s->t4) == 0) { s->tx_page_number++; s->ecm_block = 0; @@ -453,7 +456,7 @@ static int rx_start_page(t30_state_t *s) t4_rx_set_x_resolution(&s->t4, s->x_resolution); t4_rx_set_y_resolution(&s->t4, s->y_resolution); - if (t4_rx_start_page(&(s->t4))) + if (t4_rx_start_page(&s->t4)) return -1; /* Clear the buffer */ for (i = 0; i < 256; i++) @@ -468,7 +471,7 @@ static int rx_start_page(t30_state_t *s) static int rx_end_page(t30_state_t *s) { - if (t4_rx_end_page(&(s->t4)) == 0) + if (t4_rx_end_page(&s->t4) == 0) { s->rx_page_number++; s->ecm_block = 0; @@ -619,7 +622,7 @@ static uint8_t check_next_tx_step(t30_state_t *s) int res; int more; - res = t4_tx_next_page_has_different_format(&(s->t4)); + res = t4_tx_next_page_has_different_format(&s->t4); if (res == 0) { span_log(&s->logging, SPAN_LOG_FLOW, "More pages to come with the same format\n"); @@ -628,7 +631,7 @@ static uint8_t check_next_tx_step(t30_state_t *s) if (res > 0) { span_log(&s->logging, SPAN_LOG_FLOW, "More pages to come with a different format\n"); - s->tx_start_page = t4_tx_get_current_page_in_file(&(s->t4)) + 1; + s->tx_start_page = t4_tx_get_current_page_in_file(&s->t4) + 1; return (s->local_interrupt_pending) ? T30_PRI_EOM : T30_EOM; } /* Call a user handler, if one is set, to check if another document is to be sent. @@ -640,7 +643,7 @@ static uint8_t check_next_tx_step(t30_state_t *s) more = FALSE; if (more) { - //if (test_ctrl_bit(s->far_dis_dtc_frame, 34)) + //if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MULTIPLE_SELECTIVE_POLLING_CAPABLE)) // return T30_EOS; return (s->local_interrupt_pending) ? T30_PRI_EOM : T30_EOM; } @@ -690,7 +693,7 @@ static int get_partial_ecm_page(t30_state_t *s) /* We filled the entire buffer */ s->ecm_frames = 256; span_log(&s->logging, SPAN_LOG_FLOW, "Partial page buffer full (%d per frame)\n", s->octets_per_ecm_frame); - s->ecm_at_page_end = ((t4_tx_check_bit(&(s->t4)) & 2) != 0); + s->ecm_at_page_end = ((t4_tx_check_bit(&s->t4) & 2) != 0); return 256; } /*- End of function --------------------------------------------------------*/ @@ -900,28 +903,28 @@ static int send_ident_frame(t30_state_t *s, uint8_t cmd) static int send_psa_frame(t30_state_t *s) { - if (test_ctrl_bit(s->far_dis_dtc_frame, 35) && s->tx_info.polled_sub_address[0]) + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE) && s->tx_info.polled_sub_address[0]) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending polled sub-address '%s'\n", s->tx_info.polled_sub_address); send_20digit_msg_frame(s, T30_PSA, s->tx_info.polled_sub_address); - set_ctrl_bit(s->local_dis_dtc_frame, 35); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE); return TRUE; } - clr_ctrl_bit(s->local_dis_dtc_frame, 35); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE); return FALSE; } /*- End of function --------------------------------------------------------*/ static int send_sep_frame(t30_state_t *s) { - if (test_ctrl_bit(s->far_dis_dtc_frame, 47) && s->tx_info.selective_polling_address[0]) + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE) && s->tx_info.selective_polling_address[0]) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending selective polling address '%s'\n", s->tx_info.selective_polling_address); send_20digit_msg_frame(s, T30_SEP, s->tx_info.selective_polling_address); - set_ctrl_bit(s->local_dis_dtc_frame, 47); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE); return TRUE; } - clr_ctrl_bit(s->local_dis_dtc_frame, 47); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE); return FALSE; } /*- End of function --------------------------------------------------------*/ @@ -929,14 +932,14 @@ static int send_sep_frame(t30_state_t *s) static int send_sid_frame(t30_state_t *s) { /* Only send if there is an ID to send. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, 50) && s->tx_info.sender_ident[0]) + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_PASSWORD) && s->tx_info.sender_ident[0]) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending sender identification '%s'\n", s->tx_info.sender_ident); send_20digit_msg_frame(s, T30_SID, s->tx_info.sender_ident); - set_ctrl_bit(s->dcs_frame, 50); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SENDER_ID_TRANSMISSION); return TRUE; } - clr_ctrl_bit(s->dcs_frame, 50); + clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SENDER_ID_TRANSMISSION); return FALSE; } /*- End of function --------------------------------------------------------*/ @@ -944,14 +947,14 @@ static int send_sid_frame(t30_state_t *s) static int send_pwd_frame(t30_state_t *s) { /* Only send if there is a password to send. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, 50) && s->tx_info.password[0]) + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_PASSWORD) && s->tx_info.password[0]) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending password '%s'\n", s->tx_info.password); send_20digit_msg_frame(s, T30_PWD, s->tx_info.password); - set_ctrl_bit(s->local_dis_dtc_frame, 50); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_PASSWORD); return TRUE; } - clr_ctrl_bit(s->local_dis_dtc_frame, 50); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_PASSWORD); return FALSE; } /*- End of function --------------------------------------------------------*/ @@ -959,21 +962,21 @@ static int send_pwd_frame(t30_state_t *s) static int send_sub_frame(t30_state_t *s) { /* Only send if there is a sub-address to send. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, 49) && s->tx_info.sub_address[0]) + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_SUBADDRESSING_CAPABLE) && s->tx_info.sub_address[0]) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending sub-address '%s'\n", s->tx_info.sub_address); send_20digit_msg_frame(s, T30_SUB, s->tx_info.sub_address); - set_ctrl_bit(s->dcs_frame, 49); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SUBADDRESS_TRANSMISSION); return TRUE; } - clr_ctrl_bit(s->dcs_frame, 49); + clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SUBADDRESS_TRANSMISSION); return FALSE; } /*- End of function --------------------------------------------------------*/ static int send_tsa_frame(t30_state_t *s) { - if ((test_ctrl_bit(s->far_dis_dtc_frame, 1) || test_ctrl_bit(s->far_dis_dtc_frame, 3)) && 0) + if ((test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T37) || test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38)) && 0) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending transmitting subscriber internet address '%s'\n", ""); return TRUE; @@ -984,20 +987,20 @@ static int send_tsa_frame(t30_state_t *s) static int send_ira_frame(t30_state_t *s) { - if (test_ctrl_bit(s->far_dis_dtc_frame, 102) && 0) + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INTERNET_ROUTING_ADDRESS) && 0) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending internet routing address '%s'\n", ""); - set_ctrl_bit(s->dcs_frame, 102); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INTERNET_ROUTING_ADDRESS_TRANSMISSION); return TRUE; } - clr_ctrl_bit(s->dcs_frame, 102); + clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INTERNET_ROUTING_ADDRESS_TRANSMISSION); return FALSE; } /*- End of function --------------------------------------------------------*/ static int send_cia_frame(t30_state_t *s) { - if ((test_ctrl_bit(s->far_dis_dtc_frame, 1) || test_ctrl_bit(s->far_dis_dtc_frame, 3)) && 0) + if ((test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T37) || test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38)) && 0) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending calling subscriber internet address '%s'\n", ""); return TRUE; @@ -1008,13 +1011,13 @@ static int send_cia_frame(t30_state_t *s) static int send_isp_frame(t30_state_t *s) { - if (test_ctrl_bit(s->far_dis_dtc_frame, 101) && 0) + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS) && 0) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending internet selective polling address '%s'\n", ""); - set_ctrl_bit(s->local_dis_dtc_frame, 101); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS); return TRUE; } - clr_ctrl_bit(s->local_dis_dtc_frame, 101); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS); return FALSE; } /*- End of function --------------------------------------------------------*/ @@ -1058,14 +1061,14 @@ static int set_dis_or_dtc(t30_state_t *s) s->local_dis_dtc_frame[2] = (uint8_t) (T30_DIS | s->dis_received); /* If we have a file name to receive into, then we are receive capable */ if (s->rx_file[0]) - set_ctrl_bit(s->local_dis_dtc_frame, 10); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT); else - clr_ctrl_bit(s->local_dis_dtc_frame, 10); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT); /* If we have a file name to transmit, then we are ready to transmit (polling) */ if (s->tx_file[0]) - set_ctrl_bit(s->local_dis_dtc_frame, 9); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT); else - clr_ctrl_bit(s->local_dis_dtc_frame, 9); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT); return 0; } /*- End of function --------------------------------------------------------*/ @@ -1088,9 +1091,9 @@ int t30_build_dis_or_dtc(t30_state_t *s) /* Always say 256 octets per ECM frame preferred, as 64 is never used in the real world. */ if ((s->iaf & T30_IAF_MODE_T37)) - set_ctrl_bit(s->local_dis_dtc_frame, 1); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T37); if ((s->iaf & T30_IAF_MODE_T38)) - set_ctrl_bit(s->local_dis_dtc_frame, 3); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38); /* No 3G mobile */ /* No V.8 */ /* 256 octets preferred - don't bother making this optional, as everything uses 256 */ @@ -1121,57 +1124,67 @@ int t30_build_dis_or_dtc(t30_state_t *s) /* No scan-line padding required, but some may be specified by the application. */ set_ctrl_bits(s->local_dis_dtc_frame, s->local_min_scan_time_code, 21); if ((s->supported_compressions & T30_SUPPORT_NO_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, 26); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_UNCOMPRESSED_CAPABLE); if (s->ecm_allowed) { /* ECM allowed */ - set_ctrl_bit(s->local_dis_dtc_frame, 27); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_ECM_CAPABLE); /* Only offer the option of fancy compression schemes, if we are also offering the ECM option needed to support them. */ if ((s->supported_compressions & T30_SUPPORT_T6_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, 31); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE); if ((s->supported_compressions & T30_SUPPORT_T43_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, 36); - if ((s->supported_compressions & T30_SUPPORT_T85_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, 78); - /* No T.85 optional L0. */ + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE); +#if 0 if ((s->supported_compressions & T30_SUPPORT_T45_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, 116); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE); + if ((s->supported_compressions & T30_SUPPORT_T81_COMPRESSION)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE); + if ((s->supported_compressions & T30_SUPPORT_SYCC_T81_COMPRESSION)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE); + if ((s->supported_compressions & T30_SUPPORT_T85_COMPRESSION)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE); + /* No T.85 optional L0. */ + //if ((s->supported_compressions & T30_SUPPORT_T85_L0_COMPRESSION)) + // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE); + //if ((s->supported_compressions & T30_SUPPORT_T89_COMPRESSION)) + // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T89_CAPABLE); +#endif } if ((s->supported_t30_features & T30_SUPPORT_FIELD_NOT_VALID)) - set_ctrl_bit(s->local_dis_dtc_frame, 33); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FNV_CAPABLE); if ((s->supported_t30_features & T30_SUPPORT_MULTIPLE_SELECTIVE_POLLING)) - set_ctrl_bit(s->local_dis_dtc_frame, 34); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_MULTIPLE_SELECTIVE_POLLING_CAPABLE); if ((s->supported_t30_features & T30_SUPPORT_POLLED_SUB_ADDRESSING)) - set_ctrl_bit(s->local_dis_dtc_frame, 35); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE); /* No plane interleave */ /* No G.726 */ /* No extended voice coding */ if ((s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, 41); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE); if ((s->supported_resolutions & T30_SUPPORT_300_300_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, 42); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_300_300_CAPABLE); if ((s->supported_resolutions & (T30_SUPPORT_400_400_RESOLUTION | T30_SUPPORT_R16_RESOLUTION))) - set_ctrl_bit(s->local_dis_dtc_frame, 43); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE); /* Metric */ - set_ctrl_bit(s->local_dis_dtc_frame, 45); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED); /* Superfine minimum scan line time pattern follows fine */ if ((s->supported_t30_features & T30_SUPPORT_SELECTIVE_POLLING)) - set_ctrl_bit(s->local_dis_dtc_frame, 47); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE); if ((s->supported_t30_features & T30_SUPPORT_SUB_ADDRESSING)) - set_ctrl_bit(s->local_dis_dtc_frame, 49); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SUBADDRESSING_CAPABLE); if ((s->supported_t30_features & T30_SUPPORT_IDENTIFICATION)) - set_ctrl_bit(s->local_dis_dtc_frame, 50); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_PASSWORD); /* Ready to transmit a data file (polling) */ if (s->tx_file[0]) - set_ctrl_bit(s->local_dis_dtc_frame, 51); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_DATA_FILE); /* No Binary file transfer (BFT) */ /* No Document transfer mode (DTM) */ /* No Electronic data interchange (EDI) */ /* No Basic transfer mode (BTM) */ /* No mixed mode (polling) */ /* No character mode */ - /* No mixed mode (Annex E/T.4) */ + /* No mixed mode (T.4/Annex E) */ /* No mode 26 (T.505) */ /* No digital network capability */ /* No duplex operation */ @@ -1182,9 +1195,9 @@ int t30_build_dis_or_dtc(t30_state_t *s) /* No custom illuminant */ /* No custom gamut range */ if ((s->supported_image_sizes & T30_SUPPORT_US_LETTER_LENGTH)) - set_ctrl_bit(s->local_dis_dtc_frame, 76); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE); if ((s->supported_image_sizes & T30_SUPPORT_US_LEGAL_LENGTH)) - set_ctrl_bit(s->local_dis_dtc_frame, 77); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE); /* No HKM key management */ /* No RSA key management */ /* No override */ @@ -1201,19 +1214,19 @@ int t30_build_dis_or_dtc(t30_state_t *s) /* No simple phase C BFT negotiations */ /* No extended BFT negotiations */ if ((s->supported_t30_features & T30_SUPPORT_INTERNET_SELECTIVE_POLLING_ADDRESS)) - set_ctrl_bit(s->local_dis_dtc_frame, 101); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS); if ((s->supported_t30_features & T30_SUPPORT_INTERNET_ROUTING_ADDRESS)) - set_ctrl_bit(s->local_dis_dtc_frame, 102); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_ROUTING_ADDRESS); if ((s->supported_resolutions & T30_SUPPORT_600_600_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, 105); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_600_600_CAPABLE); if ((s->supported_resolutions & T30_SUPPORT_1200_1200_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, 106); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_1200_1200_CAPABLE); if ((s->supported_resolutions & T30_SUPPORT_300_600_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, 107); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE); if ((s->supported_resolutions & T30_SUPPORT_400_800_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, 108); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_400_800_CAPABLE); if ((s->supported_resolutions & T30_SUPPORT_600_1200_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, 109); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE); /* No colour/grey scale 600x600 */ /* No colour/grey scale 1200x1200 */ /* No double sided printing (alternate mode) */ @@ -1222,10 +1235,10 @@ int t30_build_dis_or_dtc(t30_state_t *s) /* No shared data memory */ /* No T.44 colour space */ if ((s->iaf & T30_IAF_MODE_FLOW_CONTROL)) - set_ctrl_bit(s->local_dis_dtc_frame, 121); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38_FLOW_CONTROL_CAPABLE); /* No k > 4 */ if ((s->iaf & T30_IAF_MODE_CONTINUOUS_FLOW)) - set_ctrl_bit(s->local_dis_dtc_frame, 123); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38_FAX_CAPABLE); /* No T.89 profile */ s->local_dis_dtc_len = 19; //t30_decode_dis_dtc_dcs(s, s->local_dis_dtc_frame, s->local_dis_dtc_len); @@ -1271,11 +1284,11 @@ static int build_dcs(t30_state_t *s) #if 0 /* Check for T.37 simple mode. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, 1)) - set_ctrl_bit(s->dcs_frame, 1); + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T37)) + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T37); /* Check for T.38 mode. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, 3)) - set_ctrl_bit(s->dcs_frame, 3); + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38)) + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T38); #endif /* Set to required modem rate */ @@ -1284,12 +1297,19 @@ static int build_dcs(t30_state_t *s) /* Select the compression to use. */ switch (s->line_encoding) { +#if 0 + case T4_COMPRESSION_ITU_T85: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_MODE); + //set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_L0_MODE); + set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); + break; +#endif case T4_COMPRESSION_ITU_T6: - set_ctrl_bit(s->dcs_frame, 31); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T6_MODE); set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); break; case T4_COMPRESSION_ITU_T4_2D: - set_ctrl_bit(s->dcs_frame, 16); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_2D_CODING); set_ctrl_bits(s->dcs_frame, s->min_scan_time_code, 21); break; case T4_COMPRESSION_ITU_T4_1D: @@ -1300,7 +1320,7 @@ static int build_dcs(t30_state_t *s) break; } /* We have a file to send, so tell the far end to go into receive mode. */ - set_ctrl_bit(s->dcs_frame, 10); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT); /* Set the Y resolution bits */ bad = T30_ERR_OK; switch (s->y_resolution) @@ -1312,13 +1332,13 @@ static int build_dcs(t30_state_t *s) if (!(s->supported_resolutions & T30_SUPPORT_600_1200_RESOLUTION)) bad = T30_ERR_NORESSUPPORT; else - set_ctrl_bit(s->dcs_frame, 109); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_1200); break; case T4_X_RESOLUTION_1200: if (!(s->supported_resolutions & T30_SUPPORT_1200_1200_RESOLUTION)) bad = T30_ERR_NORESSUPPORT; else - set_ctrl_bit(s->dcs_frame, 106); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_1200_1200); break; default: bad = T30_ERR_NORESSUPPORT; @@ -1332,7 +1352,7 @@ static int build_dcs(t30_state_t *s) if (!(s->supported_resolutions & T30_SUPPORT_400_800_RESOLUTION)) bad = T30_ERR_NORESSUPPORT; else - set_ctrl_bit(s->dcs_frame, 108); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_800); break; default: bad = T30_ERR_NORESSUPPORT; @@ -1346,13 +1366,13 @@ static int build_dcs(t30_state_t *s) if (!(s->supported_resolutions & T30_SUPPORT_300_600_RESOLUTION)) bad = T30_ERR_NORESSUPPORT; else - set_ctrl_bit(s->dcs_frame, 107); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_600); break; case T4_X_RESOLUTION_600: if (!(s->supported_resolutions & T30_SUPPORT_600_600_RESOLUTION)) bad = T30_ERR_NORESSUPPORT; else - set_ctrl_bit(s->dcs_frame, 105); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_600); break; default: bad = T30_ERR_NORESSUPPORT; @@ -1369,10 +1389,10 @@ static int build_dcs(t30_state_t *s) switch (s->x_resolution) { case T4_X_RESOLUTION_R8: - set_ctrl_bit(s->dcs_frame, 41); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400); break; case T4_X_RESOLUTION_R16: - set_ctrl_bit(s->dcs_frame, 43); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400); break; default: bad = T30_ERR_NORESSUPPORT; @@ -1387,7 +1407,7 @@ static int build_dcs(t30_state_t *s) if (!(s->supported_resolutions & T30_SUPPORT_300_300_RESOLUTION)) bad = T30_ERR_NORESSUPPORT; else - set_ctrl_bit(s->dcs_frame, 42); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_300); break; default: bad = T30_ERR_NORESSUPPORT; @@ -1404,7 +1424,7 @@ static int build_dcs(t30_state_t *s) switch (s->x_resolution) { case T4_X_RESOLUTION_R8: - set_ctrl_bit(s->dcs_frame, 15); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200); break; default: bad = T30_ERR_NORESSUPPORT; @@ -1434,6 +1454,8 @@ static int build_dcs(t30_state_t *s) /* Deal with the image width. The X resolution will fall in line with any valid width. */ /* Low (R4) res widths are not supported in recent versions of T.30 */ bad = T30_ERR_OK; + /* The following treats a width field of 11 like 10, which does what note 6 of Table 2/T.30 + says we should do with the invalid value 11. */ switch (s->image_width) { case T4_WIDTH_R8_A4: @@ -1451,7 +1473,7 @@ static int build_dcs(t30_state_t *s) if ((s->far_dis_dtc_frame[5] & (DISBIT2 | DISBIT1)) < 1) bad = T30_ERR_NOSIZESUPPORT; else if (!(s->supported_image_sizes & T30_SUPPORT_255MM_WIDTH)) - bad = T30_ERR_BADTIFF; + bad = T30_ERR_NOSIZESUPPORT; else set_ctrl_bit(s->dcs_frame, 17); break; @@ -1463,19 +1485,19 @@ static int build_dcs(t30_state_t *s) if ((s->far_dis_dtc_frame[5] & (DISBIT2 | DISBIT1)) < 2) bad = T30_ERR_NOSIZESUPPORT; else if (!(s->supported_image_sizes & T30_SUPPORT_303MM_WIDTH)) - bad = T30_ERR_BADTIFF; + bad = T30_ERR_NOSIZESUPPORT; else set_ctrl_bit(s->dcs_frame, 18); break; default: /* T.30 does not support this width */ - bad = T30_ERR_BADTIFF; + bad = T30_ERR_NOSIZESUPPORT; break; } if (bad != T30_ERR_OK) { s->current_status = bad; - span_log(&s->logging, SPAN_LOG_FLOW, "Image width (%d pixels) not a valid FAX image width\n", s->image_width); + span_log(&s->logging, SPAN_LOG_FLOW, "Image width (%d pixels) not an acceptable FAX image width\n", s->image_width); return -1; } switch (s->image_width) @@ -1488,36 +1510,36 @@ static int build_dcs(t30_state_t *s) case T4_WIDTH_300_A4: case T4_WIDTH_300_B4: case T4_WIDTH_300_A3: - if (!test_ctrl_bit(s->far_dis_dtc_frame, 42) && !test_ctrl_bit(s->far_dis_dtc_frame, 107)) + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_300_CAPABLE) && !test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE)) bad = T30_ERR_NOSIZESUPPORT; break; case T4_WIDTH_R16_A4: case T4_WIDTH_R16_B4: case T4_WIDTH_R16_A3: - if (!test_ctrl_bit(s->far_dis_dtc_frame, 43)) + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE)) bad = T30_ERR_NOSIZESUPPORT; break; case T4_WIDTH_600_A4: case T4_WIDTH_600_B4: case T4_WIDTH_600_A3: - if (!test_ctrl_bit(s->far_dis_dtc_frame, 105) && !test_ctrl_bit(s->far_dis_dtc_frame, 109)) + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_600_CAPABLE) && !test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE)) bad = T30_ERR_NOSIZESUPPORT; break; case T4_WIDTH_1200_A4: case T4_WIDTH_1200_B4: case T4_WIDTH_1200_A3: - if (!test_ctrl_bit(s->far_dis_dtc_frame, 106)) + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_1200_1200_CAPABLE)) bad = T30_ERR_NOSIZESUPPORT; break; default: /* T.30 does not support this width */ - bad = T30_ERR_BADTIFF; + bad = T30_ERR_NOSIZESUPPORT; break; } if (bad != T30_ERR_OK) { s->current_status = bad; - span_log(&s->logging, SPAN_LOG_FLOW, "Image width (%d pixels) not a valid FAX image width\n", s->image_width); + span_log(&s->logging, SPAN_LOG_FLOW, "Image width (%d pixels) not an acceptable FAX image width\n", s->image_width); return -1; } /* Deal with the image length */ @@ -1529,12 +1551,19 @@ static int build_dcs(t30_state_t *s) set_ctrl_bit(s->dcs_frame, 19); if (s->error_correcting_mode) - set_ctrl_bit(s->dcs_frame, 27); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_ECM); - if ((s->iaf & T30_IAF_MODE_FLOW_CONTROL) && test_ctrl_bit(s->far_dis_dtc_frame, 121)) - set_ctrl_bit(s->dcs_frame, 121); - if ((s->iaf & T30_IAF_MODE_CONTINUOUS_FLOW) && test_ctrl_bit(s->far_dis_dtc_frame, 123)) - set_ctrl_bit(s->dcs_frame, 123); + if ((s->iaf & T30_IAF_MODE_FLOW_CONTROL) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38_FLOW_CONTROL_CAPABLE)) + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T38_FLOW_CONTROL_CAPABLE); + if ((s->iaf & T30_IAF_MODE_CONTINUOUS_FLOW) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38_FAX_CAPABLE)) + { + /* Clear the modem type bits, in accordance with note 77 of Table 2/T.30 */ + clr_ctrl_bit(s->local_dis_dtc_frame, 11); + clr_ctrl_bit(s->local_dis_dtc_frame, 12); + clr_ctrl_bit(s->local_dis_dtc_frame, 13); + clr_ctrl_bit(s->local_dis_dtc_frame, 14); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T38_FAX_MODE); + } s->dcs_len = 19; //t30_decode_dis_dtc_dcs(s, s->dcs_frame, s->dcs_len); return 0; @@ -1814,10 +1843,10 @@ static void disconnect(t30_state_t *s) switch (s->operation_in_progress) { case OPERATION_IN_PROGRESS_T4_TX: - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); break; case OPERATION_IN_PROGRESS_T4_RX: - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); break; } s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; @@ -1855,16 +1884,16 @@ static int set_min_scan_time_code(t30_state_t *s) switch (s->y_resolution) { case T4_Y_RESOLUTION_SUPERFINE: - if (!test_ctrl_bit(s->far_dis_dtc_frame, 41)) + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE)) { s->current_status = T30_ERR_NORESSUPPORT; span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution.\n"); return -1; } - s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, 46)) ? 2 : 1][min_bits_field]; + s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MIN_SCAN_TIME_HALVES)) ? 2 : 1][min_bits_field]; break; case T4_Y_RESOLUTION_FINE: - if (!test_ctrl_bit(s->far_dis_dtc_frame, 15)) + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE)) { s->current_status = T30_ERR_NORESSUPPORT; span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution.\n"); @@ -1912,7 +1941,7 @@ static int start_sending_document(t30_state_t *s) must be evaluated before the minimum scan row bits can be evaluated. */ if ((min_row_bits = set_min_scan_time_code(s)) < 0) { - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; return -1; } @@ -1921,7 +1950,7 @@ static int start_sending_document(t30_state_t *s) if (tx_start_page(s)) return -1; - s->image_width = t4_tx_get_image_width(&(s->t4)); + s->image_width = t4_tx_get_image_width(&s->t4); if (s->error_correcting_mode) { if (get_partial_ecm_page(s) == 0) @@ -1933,7 +1962,7 @@ static int start_sending_document(t30_state_t *s) static int restart_sending_document(t30_state_t *s) { - t4_tx_restart_page(&(s->t4)); + t4_tx_restart_page(&s->t4); s->retries = 0; s->ecm_block = 0; send_dcs_sequence(s, TRUE); @@ -2006,11 +2035,19 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) /* 256 octets per ECM frame */ s->octets_per_ecm_frame = 256; /* Select the compression to use. */ - if (s->error_correcting_mode && (s->supported_compressions & T30_SUPPORT_T6_COMPRESSION) && test_ctrl_bit(s->far_dis_dtc_frame, 31)) +#if 0 + if (s->error_correcting_mode && (s->supported_compressions & T30_SUPPORT_T85_COMPRESSION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE)) + { + s->line_encoding = T4_COMPRESSION_ITU_T85; + } + else if (s->error_correcting_mode && (s->supported_compressions & T30_SUPPORT_T6_COMPRESSION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE)) +#else + if (s->error_correcting_mode && (s->supported_compressions & T30_SUPPORT_T6_COMPRESSION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE)) +#endif { s->line_encoding = T4_COMPRESSION_ITU_T6; } - else if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION) && test_ctrl_bit(s->far_dis_dtc_frame, 16)) + else if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) { s->line_encoding = T4_COMPRESSION_ITU_T4_2D; } @@ -2018,7 +2055,7 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) { s->line_encoding = T4_COMPRESSION_ITU_T4_1D; } - span_log(&s->logging, SPAN_LOG_FLOW, "Selected compression %d\n", s->line_encoding); + span_log(&s->logging, SPAN_LOG_FLOW, "Selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding); switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3)) { case (DISBIT6 | DISBIT4 | DISBIT3): @@ -2077,7 +2114,7 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) if (s->tx_file[0]) { span_log(&s->logging, SPAN_LOG_FLOW, "Trying to send file '%s'\n", s->tx_file); - if (!test_ctrl_bit(s->far_dis_dtc_frame, 10)) + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT)) { span_log(&s->logging, SPAN_LOG_FLOW, "%s far end cannot receive\n", t30_frametype(msg[2])); s->current_status = T30_ERR_RX_INCAPABLE; @@ -2103,7 +2140,7 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) if (s->rx_file[0]) { span_log(&s->logging, SPAN_LOG_FLOW, "Trying to receive file '%s'\n", s->rx_file); - if (!test_ctrl_bit(s->far_dis_dtc_frame, 9)) + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT)) { span_log(&s->logging, SPAN_LOG_FLOW, "%s far end cannot transmit\n", t30_frametype(msg[2])); s->current_status = T30_ERR_TX_INCAPABLE; @@ -2174,30 +2211,30 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) memset(dcs_frame + len, 0, T30_MAX_DIS_DTC_DCS_LEN - len); } - s->octets_per_ecm_frame = test_ctrl_bit(dcs_frame, 28) ? 256 : 64; + s->octets_per_ecm_frame = test_ctrl_bit(dcs_frame, T30_DCS_BIT_64_OCTET_ECM_FRAMES) ? 256 : 64; - if (test_ctrl_bit(dcs_frame, 106)) + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_1200_1200)) s->x_resolution = T4_X_RESOLUTION_1200; - else if (test_ctrl_bit(dcs_frame, 105) || test_ctrl_bit(dcs_frame, 109)) + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_600) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_1200)) s->x_resolution = T4_X_RESOLUTION_600; - else if (test_ctrl_bit(dcs_frame, 43) || test_ctrl_bit(dcs_frame, 108)) + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_400) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_800)) s->x_resolution = T4_X_RESOLUTION_R16; - else if (test_ctrl_bit(dcs_frame, 42) || test_ctrl_bit(dcs_frame, 107)) + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_300) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_600)) s->x_resolution = T4_X_RESOLUTION_300; else s->x_resolution = T4_X_RESOLUTION_R8; - if (test_ctrl_bit(dcs_frame, 106) || test_ctrl_bit(dcs_frame, 109)) + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_1200_1200) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_1200)) s->y_resolution = T4_Y_RESOLUTION_1200; - else if (test_ctrl_bit(dcs_frame, 108)) + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_800)) s->y_resolution = T4_Y_RESOLUTION_800; - else if (test_ctrl_bit(dcs_frame, 105) || test_ctrl_bit(dcs_frame, 107)) + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_600) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_600)) s->y_resolution = T4_Y_RESOLUTION_600; - else if (test_ctrl_bit(dcs_frame, 41) || test_ctrl_bit(dcs_frame, 43)) + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_400) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_400)) s->y_resolution = T4_Y_RESOLUTION_SUPERFINE; - else if (test_ctrl_bit(dcs_frame, 42)) + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_300)) s->y_resolution = T4_Y_RESOLUTION_300; - else if (test_ctrl_bit(dcs_frame, 15)) + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_200)) s->y_resolution = T4_Y_RESOLUTION_FINE; else s->y_resolution = T4_Y_RESOLUTION_STANDARD; @@ -2218,14 +2255,20 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) s->image_width = widths[i][dcs_frame[5] & (DISBIT2 | DISBIT1)]; /* Check which compression we will use. */ - if (test_ctrl_bit(dcs_frame, 31)) +#if 0 + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_MODE)) + s->line_encoding = T4_COMPRESSION_ITU_T85; + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T6_MODE)) +#else + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T6_MODE)) +#endif s->line_encoding = T4_COMPRESSION_ITU_T6; - else if (test_ctrl_bit(dcs_frame, 16)) + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_2D_CODING)) s->line_encoding = T4_COMPRESSION_ITU_T4_2D; else s->line_encoding = T4_COMPRESSION_ITU_T4_1D; span_log(&s->logging, SPAN_LOG_FLOW, "Selected compression %d\n", s->line_encoding); - if (!test_ctrl_bit(dcs_frame, 10)) + if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT)) span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Remote is not requesting receive in DCS\n"); if ((s->current_fallback = find_fallback_entry(dcs_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))) < 0) @@ -2233,7 +2276,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) span_log(&s->logging, SPAN_LOG_FLOW, "Remote asked for a modem standard we do not support\n"); return -1; } - s->error_correcting_mode = (test_ctrl_bit(dcs_frame, 27) != 0); + s->error_correcting_mode = (test_ctrl_bit(dcs_frame, T30_DCS_BIT_ECM) != 0); if (s->phase_b_handler) { @@ -2671,7 +2714,6 @@ static void process_state_b(t30_state_t *s, const uint8_t *msg, int len) { uint8_t fcf; - /* We should be sending the TCF data right now */ fcf = msg[2] & 0xFE; switch (fcf) { @@ -3055,14 +3097,14 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, case T30_COPY_QUALITY_PERFECT: case T30_COPY_QUALITY_GOOD: rx_end_page(s); - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; s->in_message = FALSE; set_state(s, T30_STATE_III_Q_MCF); break; case T30_COPY_QUALITY_POOR: rx_end_page(s); - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; s->in_message = FALSE; set_state(s, T30_STATE_III_Q_RTP); @@ -3113,14 +3155,14 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, case T30_COPY_QUALITY_PERFECT: case T30_COPY_QUALITY_GOOD: rx_end_page(s); - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; s->in_message = FALSE; set_state(s, T30_STATE_III_Q_MCF); break; case T30_COPY_QUALITY_POOR: rx_end_page(s); - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; s->in_message = FALSE; set_state(s, T30_STATE_III_Q_RTP); @@ -3140,7 +3182,7 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, case T30_COPY_QUALITY_PERFECT: case T30_COPY_QUALITY_GOOD: rx_end_page(s); - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; s->in_message = FALSE; set_state(s, T30_STATE_III_Q_MCF); @@ -3148,7 +3190,7 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, break; case T30_COPY_QUALITY_POOR: rx_end_page(s); - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; s->in_message = FALSE; set_state(s, T30_STATE_III_Q_RTP); @@ -3172,14 +3214,14 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, case T30_COPY_QUALITY_PERFECT: case T30_COPY_QUALITY_GOOD: rx_end_page(s); - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; s->in_message = FALSE; set_state(s, T30_STATE_III_Q_MCF); break; case T30_COPY_QUALITY_POOR: rx_end_page(s); - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; s->in_message = FALSE; set_state(s, T30_STATE_III_Q_RTP); @@ -3516,7 +3558,7 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; if (span_log_test(&s->logging, SPAN_LOG_FLOW)) { @@ -3530,7 +3572,7 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; send_dcn(s); if (span_log_test(&s->logging, SPAN_LOG_FLOW)) @@ -3575,7 +3617,7 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); /* TODO: should go back to T, and resend */ return_to_phase_b(s, TRUE); break; @@ -3584,7 +3626,7 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); send_dcn(s); break; } @@ -3895,7 +3937,7 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; if (span_log_test(&s->logging, SPAN_LOG_FLOW)) { @@ -3909,7 +3951,7 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; send_dcn(s); if (span_log_test(&s->logging, SPAN_LOG_FLOW)) @@ -3999,7 +4041,7 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; if (span_log_test(&s->logging, SPAN_LOG_FLOW)) { @@ -4013,7 +4055,7 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; send_dcn(s); if (span_log_test(&s->logging, SPAN_LOG_FLOW)) @@ -4119,7 +4161,7 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; if (span_log_test(&s->logging, SPAN_LOG_FLOW)) { @@ -4133,7 +4175,7 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; send_dcn(s); if (span_log_test(&s->logging, SPAN_LOG_FLOW)) @@ -5395,7 +5437,7 @@ SPAN_DECLARE_NONSTD(int) t30_non_ecm_get_bit(void *user_data) break; case T30_STATE_I: /* Transferring real data. */ - bit = t4_tx_get_bit(&(s->t4)); + bit = t4_tx_get_bit(&s->t4); break; case T30_STATE_D_POST_TCF: case T30_STATE_II_Q: @@ -5430,7 +5472,7 @@ SPAN_DECLARE(int) t30_non_ecm_get_byte(void *user_data) break; case T30_STATE_I: /* Transferring real data. */ - byte = t4_tx_get_byte(&(s->t4)); + byte = t4_tx_get_byte(&s->t4); break; case T30_STATE_D_POST_TCF: case T30_STATE_II_Q: @@ -5813,9 +5855,8 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) } break; case T30_STATE_B: - /* We have now allowed time for the last message to flush - through the system, so it is safe to report the end of the - call. */ + /* We have now allowed time for the last message to flush through + the system, so it is safe to report the end of the call. */ if (s->phase_e_handler) s->phase_e_handler(s, s->phase_e_user_data, s->current_status); set_state(s, T30_STATE_CALL_FINISHED); @@ -5989,10 +6030,13 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) SPAN_DECLARE(void) t30_timer_update(t30_state_t *s, int samples) { + int previous; + if (s->timer_t0_t1 > 0) { if ((s->timer_t0_t1 -= samples) <= 0) { + s->timer_t0_t1 = 0; if (s->far_end_detected) timer_t1_expired(s); else @@ -6002,13 +6046,21 @@ SPAN_DECLARE(void) t30_timer_update(t30_state_t *s, int samples) if (s->timer_t3 > 0) { if ((s->timer_t3 -= samples) <= 0) + { + s->timer_t3 = 0; timer_t3_expired(s); + } } if (s->timer_t2_t4 > 0) { if ((s->timer_t2_t4 -= samples) <= 0) { - switch (s->timer_t2_t4_is) + previous = s->timer_t2_t4_is; + /* Don't allow the count to be left at a small negative number. + It looks cosmetically bad in the logs. */ + s->timer_t2_t4 = 0; + s->timer_t2_t4_is = TIMER_IS_IDLE; + switch (previous) { case TIMER_IS_T1A: timer_t1a_expired(s); @@ -6037,7 +6089,10 @@ SPAN_DECLARE(void) t30_timer_update(t30_state_t *s, int samples) if (s->timer_t5 > 0) { if ((s->timer_t5 -= samples) <= 0) + { + s->timer_t5 = 0; timer_t5_expired(s); + } } } /*- End of function --------------------------------------------------------*/ @@ -6199,10 +6254,10 @@ SPAN_DECLARE(int) t30_release(t30_state_t *s) switch (s->operation_in_progress) { case OPERATION_IN_PROGRESS_T4_TX: - t4_tx_release(&(s->t4)); + t4_tx_release(&s->t4); break; case OPERATION_IN_PROGRESS_T4_RX: - t4_rx_release(&(s->t4)); + t4_rx_release(&s->t4); break; } s->operation_in_progress = OPERATION_IN_PROGRESS_NONE; diff --git a/libs/spandsp/src/t30_api.c b/libs/spandsp/src/t30_api.c index 0aa4ccf082..258e3f212d 100644 --- a/libs/spandsp/src/t30_api.c +++ b/libs/spandsp/src/t30_api.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t30_api.c,v 1.13 2009/02/03 16:28:40 steveu Exp $ + * $Id: t30_api.c,v 1.13.4.2 2009/12/19 14:18:13 steveu Exp $ */ /*! \file */ @@ -60,7 +60,8 @@ #include "spandsp/v29tx.h" #include "spandsp/v27ter_rx.h" #include "spandsp/v27ter_tx.h" -#include "spandsp/t4.h" +#include "spandsp/t4_rx.h" +#include "spandsp/t4_tx.h" #include "spandsp/t30_fcf.h" #include "spandsp/t35.h" #include "spandsp/t30.h" @@ -68,7 +69,8 @@ #include "spandsp/t30_logging.h" #include "spandsp/private/logging.h" -#include "spandsp/private/t4.h" +#include "spandsp/private/t4_rx.h" +#include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" #include "t30_local.h" @@ -83,7 +85,7 @@ SPAN_DECLARE(int) t30_set_tx_ident(t30_state_t *s, const char *id) if (strlen(id) > T30_MAX_IDENT_LEN) return -1; strcpy(s->tx_info.ident, id); - t4_tx_set_local_ident(&(s->t4), s->tx_info.ident); + t4_tx_set_local_ident(&s->t4, s->tx_info.ident); return 0; } /*- End of function --------------------------------------------------------*/ @@ -544,7 +546,7 @@ SPAN_DECLARE(int) t30_set_tx_page_header_info(t30_state_t *s, const char *info) if (strlen(info) > T30_MAX_PAGE_HEADER_INFO) return -1; strcpy(s->header_info, info); - t4_tx_set_header_info(&(s->t4), s->header_info); + t4_tx_set_header_info(&s->t4, s->header_info); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t30_logging.c b/libs/spandsp/src/t30_logging.c index d8c6060bad..abc6fa31c5 100644 --- a/libs/spandsp/src/t30_logging.c +++ b/libs/spandsp/src/t30_logging.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t30_logging.c,v 1.12 2009/04/12 09:12:10 steveu Exp $ + * $Id: t30_logging.c,v 1.12.4.2 2009/12/19 10:44:10 steveu Exp $ */ /*! \file */ @@ -60,14 +60,16 @@ #include "spandsp/v29tx.h" #include "spandsp/v27ter_rx.h" #include "spandsp/v27ter_tx.h" -#include "spandsp/t4.h" +#include "spandsp/t4_rx.h" +#include "spandsp/t4_tx.h" #include "spandsp/t30_fcf.h" #include "spandsp/t35.h" #include "spandsp/t30.h" #include "spandsp/t30_logging.h" #include "spandsp/private/logging.h" -#include "spandsp/private/t4.h" +#include "spandsp/private/t4_rx.h" +#include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" #include "t30_local.h" @@ -931,7 +933,7 @@ SPAN_DECLARE(void) t30_decode_dis_dtc_dcs(t30_state_t *s, const uint8_t *pkt, in octet_bit_field(log, pkt, 121, "Flow control capability for T.38 communication", NULL, NULL); octet_bit_field(log, pkt, 122, "K>4", NULL, NULL); octet_bit_field(log, pkt, 123, "Internet aware T.38 mode fax (not affected by data signal rate bits)", NULL, NULL); - octet_field(log, pkt, 124, 126, "T.89 (Application profiles for ITU-T Rec T.8)", t89_profile_tags); + octet_field(log, pkt, 124, 126, "T.89 (Application profiles for ITU-T Rec T.88)", t89_profile_tags); octet_bit_field(log, pkt, 127, "sYCC-JPEG coding", NULL, NULL); octet_bit_field(log, pkt, 128, "Extension indicator", NULL, NULL); if (!(pkt[18] & DISBIT8)) diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c index 8d783a3b1c..6f00df9499 100644 --- a/libs/spandsp/src/t31.c +++ b/libs/spandsp/src/t31.c @@ -25,7 +25,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t31.c,v 1.153 2009/10/05 16:33:25 steveu Exp $ + * $Id: t31.c,v 1.155.4.1 2009/12/19 10:44:10 steveu Exp $ */ /*! \file */ @@ -74,7 +74,8 @@ #include "spandsp/v17rx.h" #include "spandsp/super_tone_rx.h" #include "spandsp/modem_connect_tones.h" -#include "spandsp/t4.h" +#include "spandsp/t4_rx.h" +#include "spandsp/t4_tx.h" #include "spandsp/t30.h" #include "spandsp/t30_logging.h" #include "spandsp/t38_core.h" @@ -1293,12 +1294,12 @@ static int non_ecm_get_chunk(void *user_data, uint8_t buf[], int len) } /*- End of function --------------------------------------------------------*/ -static void tone_detected(void *user_data, int on, int level, int delay) +static void tone_detected(void *user_data, int tone, int level, int delay) { t31_state_t *s; s = (t31_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "FAX tone declared %s (%ddBm0)\n", (on) ? "on" : "off", level); + span_log(&s->logging, SPAN_LOG_FLOW, "%s detected (%ddBm0)\n", modem_connect_tone_to_str(tone), level); } /*- End of function --------------------------------------------------------*/ @@ -1509,7 +1510,7 @@ static void t31_v21_rx(t31_state_t *s) s->hdlc_tx.len = 0; s->dled = FALSE; hdlc_rx_init(&(s->audio.modems.hdlc_rx), FALSE, TRUE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept_frame, s); - fsk_rx_init(&(s->audio.modems.v21_rx), &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &(s->audio.modems.hdlc_rx)); + fsk_rx_init(&(s->audio.modems.v21_rx), &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, &(s->audio.modems.hdlc_rx)); fsk_rx_signal_cutoff(&(s->audio.modems.v21_rx), -39.09f); s->at_state.transmit = TRUE; } diff --git a/libs/spandsp/src/t38_core.c b/libs/spandsp/src/t38_core.c index c360d4e4fb..a5abc417a6 100644 --- a/libs/spandsp/src/t38_core.c +++ b/libs/spandsp/src/t38_core.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_core.c,v 1.53 2009/07/14 13:54:22 steveu Exp $ + * $Id: t38_core.c,v 1.54 2009/10/09 14:53:57 steveu Exp $ */ /*! \file */ @@ -224,17 +224,17 @@ SPAN_DECLARE(const char *) t38_cm_profile_to_str(int profile) switch (profile) { case '1': - return "G3 Facsimile Terminal: (Sending Facsimile)"; + return "G3 FAX sending terminal"; case '2': - return "G3 Facsimile Terminal: (Receiving Facsimile)"; + return "G3 FAX receiving terminal"; case '3': - return "V.34 HDX and G3 Facsimile Terminal: (Sending Facsimile)"; + return "V.34 HDX and G3 FAX sending terminal"; case '4': - return "V.34 HDX and G3 Facsimile Terminal: (Receiving Facsimile)"; + return "V.34 HDX and G3 FAX receiving terminal"; case '5': - return "V.34 HDX-only Facsimile Terminal: (Sending Facsimile)"; + return "V.34 HDX-only FAX sending terminal"; case '6': - return "V.34 HDX-only Facsimile Terminal: (Receiving Facsimile)"; + return "V.34 HDX-only FAX receiving terminal"; } return "???"; } @@ -260,10 +260,10 @@ SPAN_DECLARE(const char *) t38_jm_to_str(const uint8_t *data, int len) return "NACK: No compatible mode available"; case '1': /* Response for profiles 1 and 2 */ - return "NACK: No V.34 fax, use G3 fax"; + return "NACK: No V.34 FAX, use G3 FAX"; case '2': /* Response for profiles 5 and 6 */ - return "NACK: V.34 fax only."; + return "NACK: V.34 only FAX."; } break; } diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c index 7b221017f4..579e5aa20c 100644 --- a/libs/spandsp/src/t38_gateway.c +++ b/libs/spandsp/src/t38_gateway.c @@ -23,7 +23,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_gateway.c,v 1.164 2009/07/14 13:54:22 steveu Exp $ + * $Id: t38_gateway.c,v 1.171.4.2 2009/12/19 10:44:10 steveu Exp $ */ /*! \file */ @@ -73,7 +73,8 @@ #include "spandsp/v17rx.h" #include "spandsp/super_tone_rx.h" #include "spandsp/modem_connect_tones.h" -#include "spandsp/t4.h" +#include "spandsp/t4_rx.h" +#include "spandsp/t4_tx.h" #include "spandsp/t30_fcf.h" #include "spandsp/t35.h" #include "spandsp/t30.h" @@ -95,7 +96,8 @@ #include "spandsp/private/modem_connect_tones.h" #include "spandsp/private/hdlc.h" #include "spandsp/private/fax_modems.h" -#include "spandsp/private/t4.h" +#include "spandsp/private/t4_rx.h" +#include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" #include "spandsp/private/t38_core.h" #include "spandsp/private/t38_non_ecm_buffer.h" @@ -181,7 +183,7 @@ static void t38_hdlc_rx_put_bit(hdlc_rx_state_t *t, int new_bit); static void non_ecm_put_bit(void *user_data, int bit); static void non_ecm_remove_fill_and_put_bit(void *user_data, int bit); static void non_ecm_push_residue(t38_gateway_state_t *s); -static void tone_detected(void *user_data, int on, int level, int delay); +static void tone_detected(void *user_data, int tone, int level, int delay); static void set_rx_handler(t38_gateway_state_t *s, span_rx_handler_t *handler, void *user_data) { @@ -302,12 +304,12 @@ static int v29_v21_rx(void *user_data, const int16_t amp[], int len) } /*- End of function --------------------------------------------------------*/ -static void tone_detected(void *user_data, int on, int level, int delay) +static void tone_detected(void *user_data, int tone, int level, int delay) { t38_gateway_state_t *s; s = (t38_gateway_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "FAX tone declared %s (%ddBm0)\n", (on) ? "on" : "off", level); + span_log(&s->logging, SPAN_LOG_FLOW, "%s detected (%ddBm0)\n", modem_connect_tone_to_str(tone), level); } /*- End of function --------------------------------------------------------*/ @@ -540,16 +542,16 @@ static int set_next_tx_type(t38_gateway_state_t *s) set_rx_active(s, TRUE); break; case T38_IND_V8_ANSAM: - t->tx_bit_rate = 0; + t->tx_bit_rate = 300; break; case T38_IND_V8_SIGNAL: - t->tx_bit_rate = 0; + t->tx_bit_rate = 300; break; case T38_IND_V34_CNTL_CHANNEL_1200: - t->tx_bit_rate = 0; + t->tx_bit_rate = 1200; break; case T38_IND_V34_PRI_CHANNEL: - t->tx_bit_rate = 0; + t->tx_bit_rate = 33600; break; case T38_IND_V34_CC_RETRAIN: t->tx_bit_rate = 0; @@ -796,6 +798,13 @@ static void monitor_control_messages(t38_gateway_state_t *s, case T30_DCS | 1: /* We need to check which modem type is about to be used, so we can start the correct modem. */ + s->core.fast_bit_rate = 0; + s->core.fast_rx_modem = T38_NONE; + s->core.image_data_mode = FALSE; + s->core.short_train = FALSE; + if (from_modem) + s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_BEGIN; + /*endif*/ if (len >= 5) { /* The table is short, and not searched often, so a brain-dead linear scan seems OK */ @@ -807,8 +816,12 @@ static void monitor_control_messages(t38_gateway_state_t *s, /*endif*/ } /*endfor*/ + /* If we are processing a message from the modem side, the contents determine the fast receive modem. + we are to use. If it comes from the T.38 side the contents do not. */ s->core.fast_bit_rate = modem_codes[i].bit_rate; - s->core.fast_modem = modem_codes[i].modem_type; + if (from_modem) + s->core.fast_rx_modem = modem_codes[i].modem_type; + /*endif*/ } /*endif*/ if (len >= 6) @@ -816,26 +829,34 @@ static void monitor_control_messages(t38_gateway_state_t *s, j = (buf[5] & (DISBIT7 | DISBIT6 | DISBIT5)) >> 4; span_log(&s->logging, SPAN_LOG_FLOW, "Min bits test = 0x%X\n", buf[5]); s->core.min_row_bits = (s->core.fast_bit_rate*minimum_scan_line_times[j])/1000; - span_log(&s->logging, SPAN_LOG_FLOW, "Min bits per row = %d\n", j); + } + else + { + s->core.min_row_bits = 0; } /*endif*/ s->core.ecm_mode = (len >= 7) && (buf[6] & DISBIT3); - s->core.image_data_mode = FALSE; - s->core.short_train = FALSE; - if (from_modem) - s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_BEGIN; - /*endif*/ + span_log(&s->logging, SPAN_LOG_FLOW, "Fast rx modem = %d/%d, ECM = %d, Min bits per row = %d\n", s->core.fast_rx_modem, s->core.fast_bit_rate, s->core.ecm_mode, s->core.min_row_bits); break; case T30_PPS: case T30_PPS | 1: switch (buf[3] & 0xFE) { case T30_EOP: - case T30_EOM: - case T30_EOS: - case T30_MPS: case T30_PRI_EOP: + case T30_EOM: case T30_PRI_EOM: + case T30_EOS: +#if 0 + /* If we are hitting one of these conditions, it will take another DCS/DTC to select + the fast modem again, so abandon our idea of it. */ + s->core.fast_bit_rate = 0; + s->core.fast_rx_modem = T38_NONE; + s->core.image_data_mode = FALSE; + s->core.short_train = FALSE; +#endif + /* Fall through */ + case T30_MPS: case T30_PRI_MPS: s->core.count_page_on_mcf = TRUE; break; @@ -843,18 +864,27 @@ static void monitor_control_messages(t38_gateway_state_t *s, /*endswitch*/ break; case T30_EOP: - case T30_EOM: - case T30_EOS: - case T30_MPS: - case T30_PRI_EOP: - case T30_PRI_EOM: - case T30_PRI_MPS: case T30_EOP | 1: - case T30_EOM | 1: - case T30_EOS | 1: - case T30_MPS | 1: + case T30_PRI_EOP: case T30_PRI_EOP | 1: + case T30_EOM: + case T30_EOM | 1: + case T30_PRI_EOM: case T30_PRI_EOM | 1: + case T30_EOS: + case T30_EOS | 1: +#if 0 + /* If we are hitting one of these conditions, it will take another DCS/DTC to select + the fast modem again, so abandon our idea of t. */ + s->core.fast_bit_rate = 0; + s->core.fast_rx_modem = T38_NONE; + s->core.image_data_mode = FALSE; + s->core.short_train = FALSE; +#endif + /* Fall through */ + case T30_MPS: + case T30_MPS | 1: + case T30_PRI_MPS: case T30_PRI_MPS | 1: s->core.count_page_on_mcf = TRUE; break; @@ -1015,6 +1045,62 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, s = (t38_gateway_state_t *) user_data; xx = &s->t38x; + /* There are a couple of special cases of data type that need their own treatment. */ + switch (data_type) + { + case T38_DATA_V8: + switch (field_type) + { + case T38_FIELD_CM_MESSAGE: + if (len >= 1) + span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0])); + else + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len); + /*endif*/ + break; + case T38_FIELD_JM_MESSAGE: + if (len >= 2) + span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len)); + else + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len); + /*endif*/ + break; + case T38_FIELD_CI_MESSAGE: + if (len >= 1) + span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]); + else + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len); + /*endif*/ + break; + default: + break; + } + /*endswitch*/ + return 0; + case T38_DATA_V34_PRI_RATE: + switch (field_type) + { + case T38_FIELD_V34RATE: + if (len >= 3) + { + xx->t38.v34_rate = t38_v34rate_to_bps(buf, len); + span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", xx->t38.v34_rate); + } + else + { + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len); + } + /*endif*/ + break; + default: + break; + } + /*endswitch*/ + return 0; + default: + break; + } + /*endswitch*/ switch (field_type) { case T38_FIELD_HDLC_DATA: @@ -1352,39 +1438,6 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, /*endif*/ xx->corrupt_current_frame[0] = FALSE; break; - case T38_FIELD_CM_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0])); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len); - /*endif*/ - break; - case T38_FIELD_JM_MESSAGE: - if (len >= 2) - span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len)); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len); - /*endif*/ - break; - case T38_FIELD_CI_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len); - /*endif*/ - break; - case T38_FIELD_V34RATE: - if (len >= 3) - { - xx->t38.v34_rate = t38_v34rate_to_bps(buf, len); - span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", xx->t38.v34_rate); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len); - } - /*endif*/ - break; default: break; } @@ -1944,14 +1997,14 @@ static int restart_rx_modem(t38_gateway_state_t *s) s->core.to_t38.in_bits = 0; s->core.to_t38.out_octets = 0; } - span_log(&s->logging, SPAN_LOG_FLOW, "Restart rx modem - modem = %d, short train = %d, ECM = %d\n", s->core.fast_modem, s->core.short_train, s->core.ecm_mode); + span_log(&s->logging, SPAN_LOG_FLOW, "Restart rx modem - modem = %d, short train = %d, ECM = %d\n", s->core.fast_rx_modem, s->core.short_train, s->core.ecm_mode); hdlc_rx_init(&(s->audio.modems.hdlc_rx), FALSE, TRUE, HDLC_FRAMING_OK_THRESHOLD, NULL, s); s->audio.modems.rx_signal_present = FALSE; s->audio.modems.rx_trained = FALSE; /* Default to the transmit data being V.21, unless a faster modem pops up trained. */ s->t38x.current_tx_data_type = T38_DATA_V21; - fsk_rx_init(&(s->audio.modems.v21_rx), &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) t38_hdlc_rx_put_bit, &(s->audio.modems.hdlc_rx)); + fsk_rx_init(&(s->audio.modems.v21_rx), &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) t38_hdlc_rx_put_bit, &(s->audio.modems.hdlc_rx)); #if 0 fsk_rx_signal_cutoff(&(s->audio.modems.v21_rx), -45.5f); #endif @@ -1971,7 +2024,7 @@ static int restart_rx_modem(t38_gateway_state_t *s) /*endif*/ to_t38_buffer_init(&s->core.to_t38); s->core.to_t38.octets_per_data_packet = 1; - switch (s->core.fast_modem) + switch (s->core.fast_rx_modem) { case T38_V17_RX: v17_rx_restart(&s->audio.modems.v17_rx, s->core.fast_bit_rate, s->core.short_train); @@ -2245,7 +2298,7 @@ SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s, t38_gateway_set_nsx_suppression(s, (const uint8_t *) "\x00\x00\x00", 3, (const uint8_t *) "\x00\x00\x00", 3); s->core.to_t38.octets_per_data_packet = 1; - s->core.ecm_allowed = FALSE; + s->core.ecm_allowed = TRUE; t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0); restart_rx_modem(s); s->core.timed_mode = TIMED_MODE_STARTUP; diff --git a/libs/spandsp/src/t38_non_ecm_buffer.c b/libs/spandsp/src/t38_non_ecm_buffer.c index d10ce72163..1820981002 100644 --- a/libs/spandsp/src/t38_non_ecm_buffer.c +++ b/libs/spandsp/src/t38_non_ecm_buffer.c @@ -23,7 +23,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_non_ecm_buffer.c,v 1.9 2009/10/05 16:33:25 steveu Exp $ + * $Id: t38_non_ecm_buffer.c,v 1.9.4.1 2009/12/19 06:43:28 steveu Exp $ */ /*! \file */ @@ -57,13 +57,22 @@ #include "spandsp/private/t38_non_ecm_buffer.h" +/* Phases */ +enum +{ + TCF_AT_INITIAL_ALL_ONES = 0, + TCF_AT_ALL_ZEROS = 1, + IMAGE_WAITING_FOR_FIRST_EOL = 2, + IMAGE_IN_PROGRESS = 3 +}; + static void restart_buffer(t38_non_ecm_buffer_state_t *s) { /* This should be called when draining the buffer is complete, which should occur before any fresh data can possibly arrive to begin refilling it. */ s->octet = 0xFF; s->flow_control_fill_octet = 0xFF; - s->at_initial_all_ones = TRUE; + s->input_phase = (s->image_data_mode) ? IMAGE_WAITING_FOR_FIRST_EOL : TCF_AT_INITIAL_ALL_ONES; s->bit_stream = 0xFFFF; s->out_ptr = 0; s->in_ptr = 0; @@ -126,61 +135,164 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, cons int upper; int lower; + /* TCF consists of: + - zero or more ones, followed by + - about 1.5s of zeros + There may be a little junk at the end, as the modem shuts down. + + We can stuff with extra ones in the initial period of all ones, and we can stuff with extra + zeros once the zeros start. The thing we need to be wary about is the odd zero bit in the + midst of the ones, due to a bit error. */ + + /* Non-ECM image data consists of: + - zero or more ones, followed by + - zero or more zeros, followed by + - an EOL (end of line), which marks the start of the image, followed by + - a succession of data rows, with an EOL at the end of each, followed by + - an RTC (return to control) + There may be a little junk at the end, as the modem shuts down. + + An EOL 11 zeros followed by a one in a T.4 1D image or 11 zeros followed by a one followed + by a one or a zero in a T.4 2D image. An RTC consists of 6 EOLs in succession, with no + pixel data between them. + + We can stuff with ones until we get the first EOL into our buffer, then we can stuff with + zeros in front of each EOL at any point up the the RTC. We should not pad between the EOLs + which make up the RTC. Most FAX machines don't care about this, but a few will not recognise + the RTC if here is padding between the EOLs. + + We need to buffer whole rows before we output their beginning, so there is no possibility + of underflow mid-row. */ + + /* FoIP has latency issues, because of the fairly tight timeouts in the T.30 spec. We must + ensure our buffering does everything needed to avoid underflows, and to meet the minimum + row length requirements imposed by many mechanical FAX machines. We cannot, however, + afford to bulk up the data, by sending superfluous bytes. The resulting loop delay could + provoke an erroneous timeout of the acknowledgement signal. */ + i = 0; - if (s->at_initial_all_ones) + switch (s->input_phase) { + case TCF_AT_INITIAL_ALL_ONES: /* Dump initial 0xFF bytes. We will add enough of our own to makes things flow smoothly. If we don't strip these off, we might end up delaying the start of - forwarding by a large amount, as we could end up with a large block of 0xFF + forwarding by a substantial amount, as we could end up with a large block of 0xFF bytes before the real data begins. This is especially true with PC FAX - systems. This test is very simplistic, as a single bit error will throw it - off course. */ + systems. This test is very simplistic, as bit errors could confuse it. */ for ( ; i < len; i++) { if (buf[i] != 0xFF) { - s->at_initial_all_ones = FALSE; + s->input_phase = TCF_AT_ALL_ZEROS; + s->flow_control_fill_octet = 0x00; break; } } - } - if (s->image_data_mode) - { - /* This is image data */ + /* Fall through */ + case TCF_AT_ALL_ZEROS: + for ( ; i < len; i++) + { + s->data[s->in_ptr] = buf[i]; + s->latest_eol_ptr = s->in_ptr; + /* TODO: We can't buffer overflow, since we wrap around. However, the tail could + overwrite itself if things fall badly behind. */ + s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); + s->in_octets++; + } + break; + case IMAGE_WAITING_FOR_FIRST_EOL: + /* Dump anything up to the first EOL. Let the output side stuff with 0xFF bytes while waiting + for that first EOL. What occurs before the first EOL is expected to be a period of all ones + and then a period of all zeros. We really don't care what junk might be there. By definition, + the image only starts at the first EOL. */ for ( ; i < len; i++) { - /* Check for EOLs, because at an EOL we can pause and pump out zeros while - waiting for more incoming data. */ if (buf[i]) { /* There might be an EOL here. Look for at least 11 zeros, followed by a one, split between two octets. Between those two octets we can insert numerous zero octets as a means of flow control. Note that we stuff in blocks of 8 bits, and not at the minimal level. */ - /* Or'ing with 0x800 here is simply to avoid zero words looking like they have -1 + /* Or'ing with 0x800 here is to avoid zero words looking like they have -1 trailing zeros */ upper = bottom_bit(s->bit_stream | 0x800); lower = top_bit(buf[i]); - if (upper - lower > 3) + if ((upper - lower) > (11 - 8)) { + /* This is an EOL - our first row is beginning. */ + s->input_phase = IMAGE_IN_PROGRESS; + /* Start a new row */ + s->row_bits = lower - 8; + s->latest_eol_ptr = s->in_ptr; + s->flow_control_fill_octet = 0x00; + + /* If we push out two bytes of zero, and our latest non-zero byte + we should definitely form a proper EOL to begin things, with a + few harmless extra zero bits at the front. */ + s->data[s->in_ptr] = 0x00; + s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); + s->data[s->in_ptr] = 0x00; + s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); + s->data[s->in_ptr] = buf[i]; + s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); + s->in_octets += 3; + s->bit_stream = (s->bit_stream << 8) | buf[i]; + i++; + break; + } + } + s->bit_stream = (s->bit_stream << 8) | buf[i]; + } + if (i >= len) + break; + /* Fall through */ + case IMAGE_IN_PROGRESS: + /* Now we have seen an EOL, we can stuff with zeros just in front of that EOL, or any + subsequent EOL that does not immediately follow a previous EOL (i.e. a candidate RTC). + We need to track our way through the image data, allowing the output side to only send + up to the last EOL. This prevents the possibility of underflow mid-row, where we cannot + safely stuff anything in the bit stream. */ + for ( ; i < len; i++) + { + if (buf[i]) + { + /* There might be an EOL here. Look for at least 11 zeros, followed by a one, split + between two octets. Between those two octets we can insert numerous zero octets + as a means of flow control. Note that we stuff in blocks of 8 bits, and not at + the minimal level. */ + /* Or'ing with 0x800 here is to avoid zero words looking like they have -1 + trailing zeros */ + upper = bottom_bit(s->bit_stream | 0x800); + lower = top_bit(buf[i]); + if ((upper - lower) > (11 - 8)) + { + /* This is an EOL. */ s->row_bits += (8 - lower); - /* If the row is too short, extend it in chunks of a whole byte. */ - /* TODO: extend by the precise amount we should, instead of this - rough approach. */ - while (s->row_bits < s->min_row_bits) + /* Make sure we don't stretch back to back EOLs, as that could spoil the RTC. + This is a slightly crude check, as we don't know if we are processing a T.4 1D + or T.4 2D image. Accepting 12 or 12 bits apart as meaning back to back is fine, + as no 1D image row could be 1 bit long. */ + if (s->row_bits < 12 || s->row_bits > 13) { - s->min_row_bits_fill_octets++; - s->data[s->in_ptr] = 0; - s->row_bits += 8; - /* TODO: We can't buffer overflow, since we wrap around. However, the tail could - overwrite itself if things fall badly behind. */ - s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); + /* If the row is too short, extend it in chunks of a whole byte. */ + /* TODO: extend by the precise amount we should, instead of this + rough approach. */ + while (s->row_bits < s->min_bits_per_row) + { + s->min_row_bits_fill_octets++; + s->data[s->in_ptr] = 0; + s->row_bits += 8; + /* TODO: We can't buffer overflow, since we wrap around. However, + the tail could overwrite itself if things fall badly behind. */ + s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); + } + /* This is now the limit for the output side, before it starts + stuffing. */ + s->latest_eol_ptr = s->in_ptr; } /* Start a new row */ s->row_bits = lower - 8; s->in_rows++; - s->latest_eol_ptr = s->in_ptr; - s->flow_control_fill_octet = 0x00; } } s->bit_stream = (s->bit_stream << 8) | buf[i]; @@ -191,26 +303,7 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, cons s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); s->in_octets++; } - } - else - { - /* This is TCF data */ - for ( ; i < len; i++) - { - /* Check for zero bytes, as we can pause and pump out zeros while waiting - for more incoming data. Of course, the entire TCF data should be zero, - but it might not be, due to bit errors, or something weird happening. */ - if (buf[i] == 0x00) - { - s->latest_eol_ptr = s->in_ptr; - s->flow_control_fill_octet = 0x00; - } - s->data[s->in_ptr] = buf[i]; - /* TODO: We can't buffer overflow, since we wrap around. However, the tail could - overwrite itself if things fall badly behind. */ - s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); - s->in_octets++; - } + break; } } /*- End of function --------------------------------------------------------*/ @@ -249,14 +342,14 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_st } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits) +SPAN_DECLARE(void) t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, int mode, int min_bits_per_row) { s->image_data_mode = mode; - s->min_row_bits = min_row_bits; + s->min_bits_per_row = min_bits_per_row; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits) +SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, int mode, int min_bits_per_row) { if (s == NULL) { @@ -264,12 +357,9 @@ SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_b return NULL; } memset(s, 0, sizeof(*s)); - s->octet = 0xFF; - s->flow_control_fill_octet = 0xFF; - s->at_initial_all_ones = TRUE; - s->bit_stream = 0xFFFF; s->image_data_mode = mode; - s->min_row_bits = min_row_bits; + s->min_bits_per_row = min_bits_per_row; + restart_buffer(s); return s; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t38_terminal.c b/libs/spandsp/src/t38_terminal.c index 1e9c70926f..c11a95e943 100644 --- a/libs/spandsp/src/t38_terminal.c +++ b/libs/spandsp/src/t38_terminal.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_terminal.c,v 1.128 2009/09/04 14:38:46 steveu Exp $ + * $Id: t38_terminal.c,v 1.129.4.2 2009/12/19 10:44:10 steveu Exp $ */ /*! \file */ @@ -63,7 +63,8 @@ #include "spandsp/v27ter_rx.h" #include "spandsp/v17tx.h" #include "spandsp/v17rx.h" -#include "spandsp/t4.h" +#include "spandsp/t4_rx.h" +#include "spandsp/t4_tx.h" #include "spandsp/t30_fcf.h" #include "spandsp/t35.h" #include "spandsp/t30.h" @@ -73,7 +74,8 @@ #include "spandsp/t38_terminal.h" #include "spandsp/private/logging.h" -#include "spandsp/private/t4.h" +#include "spandsp/private/t4_rx.h" +#include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" #include "spandsp/private/t38_core.h" #include "spandsp/private/t38_terminal.h" @@ -231,8 +233,6 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica front_end_status(s, T30_FRONT_END_CED_PRESENT); break; case T38_IND_V21_PREAMBLE: - /* Some T.38 implementations insert these preamble indicators between HDLC frames, so - we need to be tolerant of that. */ fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT); break; @@ -248,6 +248,8 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica case T38_IND_V17_12000_LONG_TRAINING: case T38_IND_V17_14400_SHORT_TRAINING: case T38_IND_V17_14400_LONG_TRAINING: + case T38_IND_V34_CNTL_CHANNEL_1200: + case T38_IND_V34_PRI_CHANNEL: case T38_IND_V33_12000_TRAINING: case T38_IND_V33_14400_TRAINING: /* We really don't care what kind of modem is delivering the following image data. @@ -257,22 +259,30 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica break; case T38_IND_V8_ANSAM: case T38_IND_V8_SIGNAL: - case T38_IND_V34_CNTL_CHANNEL_1200: - case T38_IND_V34_PRI_CHANNEL: case T38_IND_V34_CC_RETRAIN: /* V.34 support is a work in progress. */ - front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT); break; default: front_end_status(s, T30_FRONT_END_SIGNAL_ABSENT); break; } + /*endswitch*/ fe->hdlc_rx.len = 0; fe->rx_data_missing = FALSE; return 0; } /*- End of function --------------------------------------------------------*/ +static int fake_rx_indicator(t38_core_state_t *t, t38_terminal_state_t *s, int indicator) +{ + int ret; + + ret = process_rx_indicator(t, s, indicator); + t->current_rx_indicator = indicator; + return ret; +} +/*- End of function --------------------------------------------------------*/ + static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len) { t38_terminal_state_t *s; @@ -285,29 +295,64 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, s = (t38_terminal_state_t *) user_data; fe = &s->t38_fe; -#if 0 - /* In termination mode we don't care very much what the data type is. */ + /* In termination mode we don't care very much what the data type is apart from a couple of + special cases. */ switch (data_type) { - case T38_DATA_V21: - case T38_DATA_V27TER_2400: - case T38_DATA_V27TER_4800: - case T38_DATA_V29_7200: - case T38_DATA_V29_9600: - case T38_DATA_V17_7200: - case T38_DATA_V17_9600: - case T38_DATA_V17_12000: - case T38_DATA_V17_14400: case T38_DATA_V8: + switch (field_type) + { + case T38_FIELD_CM_MESSAGE: + if (len >= 1) + span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0])); + else + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len); + //front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); + break; + case T38_FIELD_JM_MESSAGE: + if (len >= 2) + span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len)); + else + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len); + //front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); + break; + case T38_FIELD_CI_MESSAGE: + if (len >= 1) + span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]); + else + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len); + //front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); + break; + default: + break; + } + /*endswitch*/ + return 0; case T38_DATA_V34_PRI_RATE: - case T38_DATA_V34_CC_1200: - case T38_DATA_V34_PRI_CH: - case T38_DATA_V33_12000: - case T38_DATA_V33_14400: + switch (field_type) + { + case T38_FIELD_V34RATE: + if (len >= 3) + { + /* Just get and store the rate. The front end has no real interest in the + actual bit rate. */ + fe->t38.v34_rate = t38_v34rate_to_bps(buf, len); + span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", fe->t38.v34_rate); + } + else + { + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len); + } + break; + default: + break; + } + /*endswitch*/ + return 0; default: break; } -#endif + /*endswitch*/ switch (field_type) { case T38_FIELD_HDLC_DATA: @@ -316,8 +361,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, /* HDLC can just start without any signal indicator on some platforms, even when there is zero packet lost. Nasty, but true. Its a good idea to be tolerant of loss, though, so accepting a sudden start of HDLC data is the right thing to do. */ - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT); + fake_rx_indicator(t, s, T38_IND_V21_PREAMBLE); /* All real HDLC messages in the FAX world start with 0xFF. If this one is not starting with 0xFF it would appear some octets must have been missed before this one. */ if (len <= 0 || buf[0] != 0xFF) @@ -386,7 +430,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, } fe->hdlc_rx.len = 0; fe->rx_data_missing = FALSE; - fe->timeout_rx_samples = 0; + /* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */ + fake_rx_indicator(t, s, T38_IND_NO_SIGNAL); break; case T38_FIELD_HDLC_FCS_BAD_SIG_END: if (len > 0) @@ -406,7 +451,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, } fe->hdlc_rx.len = 0; fe->rx_data_missing = FALSE; - fe->timeout_rx_samples = 0; + /* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */ + fake_rx_indicator(t, s, T38_IND_NO_SIGNAL); break; case T38_FIELD_HDLC_SIG_END: if (len > 0) @@ -428,9 +474,10 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. */ fe->hdlc_rx.len = 0; fe->rx_data_missing = FALSE; - fe->timeout_rx_samples = 0; front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); } + /* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */ + fake_rx_indicator(t, s, T38_IND_NO_SIGNAL); break; case T38_FIELD_T4_NON_ECM_DATA: if (!fe->rx_signal_present) @@ -468,40 +515,13 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); } fe->rx_signal_present = FALSE; - fe->timeout_rx_samples = 0; - break; - case T38_FIELD_CM_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0])); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len); - break; - case T38_FIELD_JM_MESSAGE: - if (len >= 2) - span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len)); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len); - break; - case T38_FIELD_CI_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len); - break; - case T38_FIELD_V34RATE: - if (len >= 3) - { - fe->t38.v34_rate = t38_v34rate_to_bps(buf, len); - span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", fe->t38.v34_rate); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len); - } + /* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */ + fake_rx_indicator(t, s, T38_IND_NO_SIGNAL); break; default: break; } + /*endswitch*/ return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_rx.c b/libs/spandsp/src/t4_rx.c new file mode 100644 index 0000000000..b5321a5540 --- /dev/null +++ b/libs/spandsp/src/t4_rx.c @@ -0,0 +1,1227 @@ +//#define T4_STATE_DEBUGGING +/* + * SpanDSP - a series of DSP components for telephony + * + * t4_rx.c - ITU T.4 FAX receive processing + * + * Written by Steve Underwood + * + * Copyright (C) 2003, 2007 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: t4_rx.c,v 1.12.2.8 2009/12/21 17:18:39 steveu Exp $ + */ + +/* + * Much of this file is based on the T.4 and T.6 support in libtiff, which requires + * the following notice in any derived source code: + * + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Decoder support is derived from code in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include "floating_fudge.h" +#include + +#include "spandsp/telephony.h" +#include "spandsp/logging.h" +#include "spandsp/bit_operations.h" +#include "spandsp/async.h" +#include "spandsp/t4_rx.h" +#include "spandsp/t4_tx.h" +#include "spandsp/version.h" + +#include "spandsp/private/logging.h" +#include "spandsp/private/t4_rx.h" +#include "spandsp/private/t4_tx.h" + +/*! The number of centimetres in one inch */ +#define CM_PER_INCH 2.54f + +/*! The number of EOLs to expect at the end of a T.4 page */ +#define EOLS_TO_END_ANY_RX_PAGE 6 +/*! The number of EOLs to check at the end of a T.4 page */ +#define EOLS_TO_END_T4_RX_PAGE 5 +/*! The number of EOLs to check at the end of a T.6 page */ +#define EOLS_TO_END_T6_RX_PAGE 2 + +#if defined(T4_STATE_DEBUGGING) +static void STATE_TRACE(const char *format, ...) +{ + va_list arg_ptr; + + va_start(arg_ptr, format); + vprintf(format, arg_ptr); + va_end(arg_ptr); +} +/*- End of function --------------------------------------------------------*/ +#else +#define STATE_TRACE(...) /**/ +#endif + +/*! T.4 run length table entry */ +typedef struct +{ + /*! Length of T.4 code, in bits */ + uint16_t length; + /*! T.4 code */ + uint16_t code; + /*! Run length, in bits */ + int16_t run_length; +} t4_run_table_entry_t; + +#include "t4_t6_decode_states.h" + +#if defined(HAVE_LIBTIFF) +static int set_tiff_directory_info(t4_state_t *s) +{ + time_t now; + struct tm *tm; + char buf[256 + 1]; + uint16_t resunit; + float x_resolution; + float y_resolution; + t4_tiff_state_t *t; + + t = &s->tiff; + /* Prepare the directory entry fully before writing the image, or libtiff complains */ + TIFFSetField(t->tiff_file, TIFFTAG_COMPRESSION, t->output_compression); + if (t->output_compression == COMPRESSION_CCITT_T4) + { + TIFFSetField(t->tiff_file, TIFFTAG_T4OPTIONS, t->output_t4_options); + TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); + } + TIFFSetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, s->image_width); + TIFFSetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, 1); + TIFFSetField(t->tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(t->tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1); + if (t->output_compression == COMPRESSION_CCITT_T4 + || + t->output_compression == COMPRESSION_CCITT_T6) + { + TIFFSetField(t->tiff_file, TIFFTAG_ROWSPERSTRIP, -1L); + } + else + { + TIFFSetField(t->tiff_file, + TIFFTAG_ROWSPERSTRIP, + TIFFDefaultStripSize(t->tiff_file, 0)); + } + TIFFSetField(t->tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); + TIFFSetField(t->tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB); + + x_resolution = s->x_resolution/100.0f; + y_resolution = s->y_resolution/100.0f; + /* Metric seems the sane thing to use in the 21st century, but a lot of lousy software + gets FAX resolutions wrong, and more get it wrong using metric than using inches. */ +#if 0 + TIFFSetField(t->tiff_file, TIFFTAG_XRESOLUTION, x_resolution); + TIFFSetField(t->tiff_file, TIFFTAG_YRESOLUTION, y_resolution); + resunit = RESUNIT_CENTIMETER; + TIFFSetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, resunit); +#else + TIFFSetField(t->tiff_file, TIFFTAG_XRESOLUTION, floorf(x_resolution*CM_PER_INCH + 0.5f)); + TIFFSetField(t->tiff_file, TIFFTAG_YRESOLUTION, floorf(y_resolution*CM_PER_INCH + 0.5f)); + resunit = RESUNIT_INCH; + TIFFSetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, resunit); +#endif + /* TODO: add the version of spandsp */ + TIFFSetField(t->tiff_file, TIFFTAG_SOFTWARE, "Spandsp " SPANDSP_RELEASE_DATETIME_STRING); + if (gethostname(buf, sizeof(buf)) == 0) + TIFFSetField(t->tiff_file, TIFFTAG_HOSTCOMPUTER, buf); + +#if defined(TIFFTAG_FAXDCS) + if (t->dcs) + TIFFSetField(t->tiff_file, TIFFTAG_FAXDCS, t->dcs); +#endif + if (t->sub_address) + TIFFSetField(t->tiff_file, TIFFTAG_FAXSUBADDRESS, t->sub_address); + if (t->far_ident) + TIFFSetField(t->tiff_file, TIFFTAG_IMAGEDESCRIPTION, t->far_ident); + if (t->vendor) + TIFFSetField(t->tiff_file, TIFFTAG_MAKE, t->vendor); + if (t->model) + TIFFSetField(t->tiff_file, TIFFTAG_MODEL, t->model); + + time(&now); + tm = localtime(&now); + sprintf(buf, + "%4d/%02d/%02d %02d:%02d:%02d", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + TIFFSetField(t->tiff_file, TIFFTAG_DATETIME, buf); + TIFFSetField(t->tiff_file, TIFFTAG_FAXRECVTIME, now - s->page_start_time); + + TIFFSetField(t->tiff_file, TIFFTAG_IMAGELENGTH, s->image_length); + /* Set the total pages to 1. For any one page document we will get this + right. For multi-page documents we will need to come back and fill in + the right answer when we know it. */ + TIFFSetField(t->tiff_file, TIFFTAG_PAGENUMBER, s->current_page++, 1); + s->tiff.pages_in_file = s->current_page; + if (t->output_compression == COMPRESSION_CCITT_T4) + { + if (s->t4_t6_rx.bad_rows) + { + TIFFSetField(t->tiff_file, TIFFTAG_BADFAXLINES, s->t4_t6_rx.bad_rows); + TIFFSetField(t->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_REGENERATED); + TIFFSetField(t->tiff_file, TIFFTAG_CONSECUTIVEBADFAXLINES, s->t4_t6_rx.longest_bad_row_run); + } + else + { + TIFFSetField(t->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); + } + } + TIFFSetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, s->image_width); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int open_tiff_output_file(t4_state_t *s, const char *file) +{ + if ((s->tiff.tiff_file = TIFFOpen(file, "w")) == NULL) + return -1; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static void write_tiff_image(t4_state_t *s) +{ + /* Set up the TIFF directory info... */ + set_tiff_directory_info(s); + /* ..and then write the image... */ + if (TIFFWriteEncodedStrip(s->tiff.tiff_file, 0, s->image_buffer, s->image_length*s->bytes_per_row) < 0) + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", s->tiff.file); + /* ...then the directory entry, and libtiff is happy. */ + TIFFWriteDirectory(s->tiff.tiff_file); +} +/*- End of function --------------------------------------------------------*/ + +static int close_tiff_output_file(t4_state_t *s) +{ + int i; + t4_tiff_state_t *t; + + t = &s->tiff; + /* Perform any operations needed to tidy up a written TIFF file before + closure. */ + if (s->current_page > 1) + { + /* We need to edit the TIFF directories. Until now we did not know + the total page count, so the TIFF file currently says one. Now we + need to set the correct total page count associated with each page. */ + for (i = 0; i < s->current_page; i++) + { + TIFFSetDirectory(t->tiff_file, (tdir_t) i); + TIFFSetField(t->tiff_file, TIFFTAG_PAGENUMBER, i, s->current_page); + TIFFWriteDirectory(t->tiff_file); + } + } + TIFFClose(t->tiff_file); + t->tiff_file = NULL; + if (t->file) + { + /* Try not to leave a file behind, if we didn't receive any pages to + put in it. */ + if (s->current_page == 0) + remove(t->file); + free((char *) t->file); + t->file = NULL; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#else + +static int set_tiff_directory_info(t4_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int get_tiff_directory_info(t4_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int test_tiff_directory_info(t4_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int open_tiff_input_file(t4_state_t *s, const char *file) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int read_tiff_image(t4_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int close_tiff_input_file(t4_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int open_tiff_output_file(t4_state_t *s, const char *file) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static void write_tiff_image(t4_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int close_tiff_output_file(t4_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +static void update_row_bit_info(t4_state_t *s) +{ + if (s->row_bits > s->max_row_bits) + s->max_row_bits = s->row_bits; + if (s->row_bits < s->min_row_bits) + s->min_row_bits = s->row_bits; + s->row_bits = 0; +} +/*- End of function --------------------------------------------------------*/ + +#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__) +static __inline__ int run_length(unsigned int bits) +{ + return 7 - top_bit(bits); +} +/*- End of function --------------------------------------------------------*/ +#else +static __inline__ int run_length(unsigned int bits) +{ + static const uint8_t run_len[256] = + { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0F */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1F */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2F */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0 - 0xFF */ + }; + + return run_len[bits]; +} +/*- End of function --------------------------------------------------------*/ +#endif + +static int free_buffers(t4_state_t *s) +{ + if (s->image_buffer) + { + free(s->image_buffer); + s->image_buffer = NULL; + s->image_buffer_size = 0; + } + if (s->cur_runs) + { + free(s->cur_runs); + s->cur_runs = NULL; + } + if (s->ref_runs) + { + free(s->ref_runs); + s->ref_runs = NULL; + } + if (s->row_buf) + { + free(s->row_buf); + s->row_buf = NULL; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void add_run_to_row(t4_state_t *s) +{ + if (s->t4_t6_rx.run_length >= 0) + { + s->row_len += s->t4_t6_rx.run_length; + /* Don't allow rows to grow too long, and overflow the buffers */ + if (s->row_len <= s->image_width) + s->cur_runs[s->t4_t6_rx.a_cursor++] = s->t4_t6_rx.run_length; + } + s->t4_t6_rx.run_length = 0; +} +/*- End of function --------------------------------------------------------*/ + +static int put_decoded_row(t4_state_t *s) +{ + static const int msbmask[9] = + { + 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff + }; + uint8_t *t; + uint32_t i; + uint32_t *p; + int fudge; + int row_starts_at; + int x; + int j; + + if (s->t4_t6_rx.run_length) + add_run_to_row(s); +#if defined(T4_STATE_DEBUGGING) + /* Dump the runs of black and white for analysis */ + { + int total; + + total = 0; + for (x = 0; x < s->t4_t6_rx.b_cursor; x++) + total += s->ref_runs[x]; + printf("Ref (%d)", total); + for (x = 0; x < s->t4_t6_rx.b_cursor; x++) + printf(" %" PRIu32, s->ref_runs[x]); + printf("\n"); + total = 0; + for (x = 0; x < s->t4_t6_rx.a_cursor; x++) + total += s->cur_runs[x]; + printf("Cur (%d)", total); + for (x = 0; x < s->t4_t6_rx.a_cursor; x++) + printf(" %" PRIu32, s->cur_runs[x]); + printf("\n"); + } +#endif + row_starts_at = s->image_size; + /* Make sure there is enough room for another row */ + if (s->image_size + s->bytes_per_row >= s->image_buffer_size) + { + if ((t = realloc(s->image_buffer, s->image_buffer_size + 100*s->bytes_per_row)) == NULL) + return -1; + s->image_buffer_size += 100*s->bytes_per_row; + s->image_buffer = t; + } + if (s->row_len == s->image_width) + { + STATE_TRACE("%d Good row - %d %s\n", s->image_length, s->row_len, (s->row_is_2d) ? "2D" : "1D"); + if (s->t4_t6_rx.curr_bad_row_run) + { + if (s->t4_t6_rx.curr_bad_row_run > s->t4_t6_rx.longest_bad_row_run) + s->t4_t6_rx.longest_bad_row_run = s->t4_t6_rx.curr_bad_row_run; + s->t4_t6_rx.curr_bad_row_run = 0; + } + /* Convert the runs to a bit image of the row */ + /* White/black/white... runs, always starting with white. That means the first run could be + zero length. */ + for (x = 0, fudge = 0; x < s->t4_t6_rx.a_cursor; x++, fudge ^= 0xFF) + { + i = s->cur_runs[x]; + if ((int) i >= s->tx_bits) + { + s->tx_bitstream = (s->tx_bitstream << s->tx_bits) | (msbmask[s->tx_bits] & fudge); + for (i += (8 - s->tx_bits); i >= 8; i -= 8) + { + s->tx_bits = 8; + s->image_buffer[s->image_size++] = (uint8_t) s->tx_bitstream; + s->tx_bitstream = fudge; + } + } + s->tx_bitstream = (s->tx_bitstream << i) | (msbmask[i] & fudge); + s->tx_bits -= i; + } + s->image_length++; + } + else + { + STATE_TRACE("%d Bad row - %d %s\n", s->image_length, s->row_len, (s->row_is_2d) ? "2D" : "1D"); + /* Try to clean up the bad runs, and produce something reasonable as the reference + row for the next row. Use a copy of the previous good row as the actual current + row. If the row only fell apart near the end, reusing it might be the best + solution. */ + for (j = 0, fudge = 0; j < s->t4_t6_rx.a_cursor && fudge < s->image_width; j++) + fudge += s->cur_runs[j]; + if (fudge < s->image_width) + { + /* Try to pad with white, and avoid black, to minimise mess on the image. */ + if ((s->t4_t6_rx.a_cursor & 1)) + { + /* We currently finish in white. We could extend that, but it is probably of + the right length. Changing it would only further mess up what happens in the + next row. It seems better to add a black spot, and an extra white run. */ + s->cur_runs[s->t4_t6_rx.a_cursor++] = 1; + fudge++; + if (fudge < s->image_width) + s->cur_runs[s->t4_t6_rx.a_cursor++] = s->image_width - fudge; + } + else + { + /* We currently finish on black, so we add an extra white run to fill out the line. */ + s->cur_runs[s->t4_t6_rx.a_cursor++] = s->image_width - fudge; + } + } + else + { + /* Trim the last element to align with the proper image width */ + s->cur_runs[s->t4_t6_rx.a_cursor] += (s->image_width - fudge); + } + /* Ensure there is a previous line to copy from. */ + if (s->image_size != s->t4_t6_rx.last_row_starts_at) + { + /* Copy the previous row over this one */ + memcpy(s->image_buffer + s->image_size, s->image_buffer + s->t4_t6_rx.last_row_starts_at, s->bytes_per_row); + s->image_size += s->bytes_per_row; + s->image_length++; + } + s->t4_t6_rx.bad_rows++; + s->t4_t6_rx.curr_bad_row_run++; + } + + /* Pad the row as it becomes the reference row, so there are no odd runs to pick up if we + step off the end of the list. */ + s->cur_runs[s->t4_t6_rx.a_cursor] = 0; + s->cur_runs[s->t4_t6_rx.a_cursor + 1] = 0; + + /* Prepare the buffers for the next row. */ + s->t4_t6_rx.last_row_starts_at = row_starts_at; + /* Swap the buffers */ + p = s->cur_runs; + s->cur_runs = s->ref_runs; + s->ref_runs = p; + + s->t4_t6_rx.b_cursor = 1; + s->t4_t6_rx.a_cursor = 0; + s->t4_t6_rx.b1 = s->ref_runs[0]; + s->t4_t6_rx.a0 = 0; + + s->t4_t6_rx.run_length = 0; + + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_rx_end_page(t4_state_t *s) +{ + int row; + int i; + + if (s->line_encoding == T4_COMPRESSION_ITU_T6) + { + /* Push enough zeros through the decoder to flush out any remaining codes */ + for (i = 0; i < 13; i++) + t4_rx_put_bit(s, 0); + } + if (s->t4_t6_rx.curr_bad_row_run) + { + if (s->t4_t6_rx.curr_bad_row_run > s->t4_t6_rx.longest_bad_row_run) + s->t4_t6_rx.longest_bad_row_run = s->t4_t6_rx.curr_bad_row_run; + s->t4_t6_rx.curr_bad_row_run = 0; + } + + if (s->image_size == 0) + return -1; + + if (s->t4_t6_rx.row_write_handler) + { + for (row = 0; row < s->image_length; row++) + { + if (s->t4_t6_rx.row_write_handler(s->t4_t6_rx.row_write_user_data, s->image_buffer + row*s->bytes_per_row, s->bytes_per_row) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "Write error at row %d.\n", row); + break; + } + } + /* Write a blank row to indicate the end of the image. */ + if (s->t4_t6_rx.row_write_handler(s->t4_t6_rx.row_write_user_data, NULL, 0) < 0) + span_log(&s->logging, SPAN_LOG_WARNING, "Write error at row %d.\n", row); + } + else + { + write_tiff_image(s); + } + s->t4_t6_rx.rx_bits = 0; + s->t4_t6_rx.rx_skip_bits = 0; + s->t4_t6_rx.rx_bitstream = 0; + s->t4_t6_rx.consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; + + s->image_size = 0; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void drop_rx_bits(t4_state_t *s, int bits) +{ + /* Only remove one bit right now. The rest need to be removed step by step, + checking for a misaligned EOL along the way. This is time consuming, but + if we don't do it a single bit error can severely damage an image. */ + s->row_bits += bits; + s->t4_t6_rx.rx_skip_bits += (bits - 1); + s->t4_t6_rx.rx_bits--; + s->t4_t6_rx.rx_bitstream >>= 1; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void force_drop_rx_bits(t4_state_t *s, int bits) +{ + /* This should only be called to drop the bits of an EOL, as that is the + only place where it is safe to drop them all at once. */ + s->row_bits += bits; + s->t4_t6_rx.rx_skip_bits = 0; + s->t4_t6_rx.rx_bits -= bits; + s->t4_t6_rx.rx_bitstream >>= bits; +} +/*- End of function --------------------------------------------------------*/ + +static int rx_put_bits(t4_state_t *s, uint32_t bit_string, int quantity) +{ + int bits; + + /* We decompress bit by bit, as the data stream is received. We need to + scan continuously for EOLs, so we might as well work this way. */ + s->line_image_size += quantity; + s->t4_t6_rx.rx_bitstream |= (bit_string << s->t4_t6_rx.rx_bits); + /* The longest item we need to scan for is 13 bits long (a 2D EOL), so we + need a minimum of 13 bits in the buffer to proceed with any bit stream + analysis. */ + if ((s->t4_t6_rx.rx_bits += quantity) < 13) + return FALSE; + if (s->t4_t6_rx.consecutive_eols) + { + /* Check if the image has already terminated. */ + if (s->t4_t6_rx.consecutive_eols >= EOLS_TO_END_ANY_RX_PAGE) + return TRUE; + /* Check if the image hasn't even started. */ + if (s->t4_t6_rx.consecutive_eols < 0) + { + /* We are waiting for the very first EOL (1D or 2D only). */ + /* We need to take this bit by bit, as the EOL could be anywhere, + and any junk could preceed it. */ + while ((s->t4_t6_rx.rx_bitstream & 0xFFF) != 0x800) + { + s->t4_t6_rx.rx_bitstream >>= 1; + if (--s->t4_t6_rx.rx_bits < 13) + return FALSE; + } + /* We have an EOL, so now the page begins and we can proceed to + process the bit stream as image data. */ + s->t4_t6_rx.consecutive_eols = 0; + if (s->line_encoding == T4_COMPRESSION_ITU_T4_1D) + { + s->row_is_2d = FALSE; + force_drop_rx_bits(s, 12); + } + else + { + s->row_is_2d = !(s->t4_t6_rx.rx_bitstream & 0x1000); + force_drop_rx_bits(s, 13); + } + } + } + + while (s->t4_t6_rx.rx_bits >= 13) + { + /* We need to check for EOLs bit by bit through the whole stream. If + we just try looking between code words, we will miss an EOL when a bit + error has throw the code words completely out of step. The can mean + recovery takes many lines, and the image gets really messed up. */ + /* Although EOLs are not inserted at the end of each row of a T.6 image, + they are still perfectly valid, and can terminate an image. */ + if ((s->t4_t6_rx.rx_bitstream & 0x0FFF) == 0x0800) + { + STATE_TRACE("EOL\n"); + if (s->row_len == 0) + { + /* A zero length row - i.e. 2 consecutive EOLs - is distinctly + the end of page condition. That's all we actually get on a + T.6 page. However, there are a minimum of 6 EOLs at the end of + any T.4 page. We can look for more than 2 EOLs in case bit + errors simulate the end of page condition at the wrong point. + Such robust checking is irrelevant for a T.6 page, as it should + be error free. */ + /* Note that for a T.6 page we should get here on the very first + EOL, as the row length should be zero at that point. Therefore + we should count up both EOLs, unless there is some bogus partial + row ahead of them. */ + s->t4_t6_rx.consecutive_eols++; + if (s->line_encoding == T4_COMPRESSION_ITU_T6) + { + if (s->t4_t6_rx.consecutive_eols >= EOLS_TO_END_T6_RX_PAGE) + { + s->t4_t6_rx.consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; + return TRUE; + } + } + else + { + if (s->t4_t6_rx.consecutive_eols >= EOLS_TO_END_T4_RX_PAGE) + { + s->t4_t6_rx.consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; + return TRUE; + } + } + } + else + { + /* The EOLs are not back-to-back, so they are not part of the + end of page condition. */ + if (s->t4_t6_rx.run_length > 0) + add_run_to_row(s); + s->t4_t6_rx.consecutive_eols = 0; + if (put_decoded_row(s)) + return TRUE; + update_row_bit_info(s); + } + if (s->line_encoding == T4_COMPRESSION_ITU_T4_2D) + { + s->row_is_2d = !(s->t4_t6_rx.rx_bitstream & 0x1000); + force_drop_rx_bits(s, 13); + } + else + { + force_drop_rx_bits(s, 12); + } + s->t4_t6_rx.its_black = FALSE; + s->t4_t6_rx.black_white = 0; + s->t4_t6_rx.run_length = 0; + s->row_len = 0; + continue; + } + if (s->t4_t6_rx.rx_skip_bits) + { + /* We are clearing out the remaining bits of the last code word we + absorbed. */ + s->t4_t6_rx.rx_skip_bits--; + s->t4_t6_rx.rx_bits--; + s->t4_t6_rx.rx_bitstream >>= 1; + continue; + } + if (s->row_is_2d && s->t4_t6_rx.black_white == 0) + { + bits = s->t4_t6_rx.rx_bitstream & 0x7F; + STATE_TRACE("State %d, %d - ", + t4_2d_table[bits].state, + t4_2d_table[bits].width); + if (s->row_len >= s->image_width) + { + drop_rx_bits(s, t4_2d_table[bits].width); + continue; + } + if (s->t4_t6_rx.a_cursor) + { + /* Move past a0, always staying on the current colour */ + for ( ; s->t4_t6_rx.b1 <= s->t4_t6_rx.a0; s->t4_t6_rx.b_cursor += 2) + s->t4_t6_rx.b1 += (s->ref_runs[s->t4_t6_rx.b_cursor] + s->ref_runs[s->t4_t6_rx.b_cursor + 1]); + } + switch (t4_2d_table[bits].state) + { + case S_Horiz: + STATE_TRACE("Horiz %d %d %d\n", + s->image_width, + s->t4_t6_rx.a0, + s->t4_t6_rx.a_cursor); + /* We now need to extract a white/black or black/white pair of runs, using the 1D + method. If the first of the pair takes us exactly to the end of the row, there + should still be a zero length element for the second of the pair. */ + s->t4_t6_rx.its_black = s->t4_t6_rx.a_cursor & 1; + s->t4_t6_rx.black_white = 2; + break; + case S_Vert: + STATE_TRACE("Vert[%d] %d %d %d %d\n", + t4_2d_table[bits].param, + s->image_width, + s->t4_t6_rx.a0, + s->t4_t6_rx.b1, + s->t4_t6_rx.run_length); + s->t4_t6_rx.run_length += (s->t4_t6_rx.b1 - s->t4_t6_rx.a0 + t4_2d_table[bits].param); + s->t4_t6_rx.a0 = s->t4_t6_rx.b1 + t4_2d_table[bits].param; + add_run_to_row(s); + /* We need to move one step in one direction or the other, to change to the + opposite colour */ + if (t4_2d_table[bits].param >= 0) + { + s->t4_t6_rx.b1 += s->ref_runs[s->t4_t6_rx.b_cursor++]; + } + else + { + if (s->t4_t6_rx.b_cursor) + s->t4_t6_rx.b1 -= s->ref_runs[--s->t4_t6_rx.b_cursor]; + } + break; + case S_Pass: + STATE_TRACE("Pass %d %d %d %d %d\n", + s->image_width, + s->t4_t6_rx.a0, + s->t4_t6_rx.b1, + s->ref_runs[s->t4_t6_rx.b_cursor], + s->ref_runs[s->t4_t6_rx.b_cursor + 1]); + s->t4_t6_rx.b1 += s->ref_runs[s->t4_t6_rx.b_cursor++]; + s->t4_t6_rx.run_length += (s->t4_t6_rx.b1 - s->t4_t6_rx.a0); + s->t4_t6_rx.a0 = s->t4_t6_rx.b1; + s->t4_t6_rx.b1 += s->ref_runs[s->t4_t6_rx.b_cursor++]; + break; + case S_Ext: + /* We do not currently handle any kind of extension */ + STATE_TRACE("Ext %d %d %d 0x%x\n", + s->image_width, + s->t4_t6_rx.a0, + ((s->t4_t6_rx.rx_bitstream >> t4_2d_table[bits].width) & 0x7), + s->t4_t6_rx.rx_bitstream); + /* TODO: The uncompressed option should be implemented. */ + break; + case S_Null: + STATE_TRACE("Null\n"); + break; + default: + STATE_TRACE("Unexpected T.4 state\n"); + span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected T.4 state %d\n", t4_2d_table[bits].state); + break; + } + drop_rx_bits(s, t4_2d_table[bits].width); + } + else + { + if (s->t4_t6_rx.its_black) + { + bits = s->t4_t6_rx.rx_bitstream & 0x1FFF; + STATE_TRACE("State %d, %d - Black %d %d %d\n", + t4_1d_black_table[bits].state, + t4_1d_black_table[bits].width, + s->image_width, + s->t4_t6_rx.a0, + t4_1d_black_table[bits].param); + switch (t4_1d_black_table[bits].state) + { + case S_MakeUpB: + case S_MakeUp: + s->t4_t6_rx.run_length += t4_1d_black_table[bits].param; + s->t4_t6_rx.a0 += t4_1d_black_table[bits].param; + break; + case S_TermB: + s->t4_t6_rx.its_black = FALSE; + if (s->row_len < s->image_width) + { + s->t4_t6_rx.run_length += t4_1d_black_table[bits].param; + s->t4_t6_rx.a0 += t4_1d_black_table[bits].param; + add_run_to_row(s); + } + if (s->t4_t6_rx.black_white) + s->t4_t6_rx.black_white--; + break; + default: + /* Bad black */ + s->t4_t6_rx.black_white = 0; + break; + } + drop_rx_bits(s, t4_1d_black_table[bits].width); + } + else + { + bits = s->t4_t6_rx.rx_bitstream & 0xFFF; + STATE_TRACE("State %d, %d - White %d %d %d\n", + t4_1d_white_table[bits].state, + t4_1d_white_table[bits].width, + s->image_width, + s->t4_t6_rx.a0, + t4_1d_white_table[bits].param); + switch (t4_1d_white_table[bits].state) + { + case S_MakeUpW: + case S_MakeUp: + s->t4_t6_rx.run_length += t4_1d_white_table[bits].param; + s->t4_t6_rx.a0 += t4_1d_white_table[bits].param; + break; + case S_TermW: + s->t4_t6_rx.its_black = TRUE; + if (s->row_len < s->image_width) + { + s->t4_t6_rx.run_length += t4_1d_white_table[bits].param; + s->t4_t6_rx.a0 += t4_1d_white_table[bits].param; + add_run_to_row(s); + } + if (s->t4_t6_rx.black_white) + s->t4_t6_rx.black_white--; + break; + default: + /* Bad white */ + s->t4_t6_rx.black_white = 0; + break; + } + drop_rx_bits(s, t4_1d_white_table[bits].width); + } + } + if (s->t4_t6_rx.a0 >= s->image_width) + s->t4_t6_rx.a0 = s->image_width - 1; + + if (s->line_encoding == T4_COMPRESSION_ITU_T6) + { + /* T.6 has no EOL markers. We sense the end of a line by its length alone. */ + /* The last test here is a backstop protection, so a corrupt image cannot + cause us to do bad things. Bad encoders have actually been seen, which + demand such protection. */ + if (s->t4_t6_rx.black_white == 0 && s->row_len >= s->image_width) + { + STATE_TRACE("EOL T.6\n"); + if (s->t4_t6_rx.run_length > 0) + add_run_to_row(s); + update_row_bit_info(s); + if (put_decoded_row(s)) + return TRUE; + s->t4_t6_rx.its_black = FALSE; + s->t4_t6_rx.black_white = 0; + s->t4_t6_rx.run_length = 0; + s->row_len = 0; + } + } + } + return FALSE; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_rx_put_bit(t4_state_t *s, int bit) +{ + return rx_put_bits(s, bit & 1, 1); +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_rx_put_byte(t4_state_t *s, uint8_t byte) +{ + return rx_put_bits(s, byte & 0xFF, 8); +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_rx_put_chunk(t4_state_t *s, const uint8_t buf[], int len) +{ + int i; + uint8_t byte; + + for (i = 0; i < len; i++) + { + byte = buf[i]; + if (rx_put_bits(s, byte & 0xFF, 8)) + return TRUE; + } + return FALSE; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_state_t *s, t4_row_write_handler_t handler, void *user_data) +{ + s->t4_t6_rx.row_write_handler = handler; + s->t4_t6_rx.row_write_user_data = user_data; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(t4_state_t *) t4_rx_init(t4_state_t *s, const char *file, int output_encoding) +{ + if (s == NULL) + { + if ((s = (t4_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + span_log_init(&s->logging, SPAN_LOG_NONE, NULL); + span_log_set_protocol(&s->logging, "T.4"); + s->rx = TRUE; + + span_log(&s->logging, SPAN_LOG_FLOW, "Start rx document\n"); + + if (open_tiff_output_file(s, file) < 0) + return NULL; + + /* Save the file name for logging reports. */ + s->tiff.file = strdup(file); + /* Only provide for one form of coding throughout the file, even though the + coding on the wire could change between pages. */ + switch (output_encoding) + { + case T4_COMPRESSION_ITU_T4_1D: + s->tiff.output_compression = COMPRESSION_CCITT_T4; + s->tiff.output_t4_options = GROUP3OPT_FILLBITS; + break; + case T4_COMPRESSION_ITU_T4_2D: + s->tiff.output_compression = COMPRESSION_CCITT_T4; + s->tiff.output_t4_options = GROUP3OPT_FILLBITS | GROUP3OPT_2DENCODING; + break; + case T4_COMPRESSION_ITU_T6: + s->tiff.output_compression = COMPRESSION_CCITT_T6; + s->tiff.output_t4_options = 0; + break; + } + + /* Until we have a valid figure for the bytes per row, we need it to be set to a suitable + value to ensure it will be seen as changing when the real value is used. */ + s->bytes_per_row = 0; + + s->current_page = 0; + s->tiff.pages_in_file = 0; + s->tiff.start_page = 0; + s->tiff.stop_page = INT_MAX; + + s->image_buffer = NULL; + s->image_buffer_size = 0; + + /* Set some default values */ + s->x_resolution = T4_X_RESOLUTION_R8; + s->y_resolution = T4_Y_RESOLUTION_FINE; + s->image_width = T4_WIDTH_R8_A4; + + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_rx_start_page(t4_state_t *s) +{ + int bytes_per_row; + int run_space; + uint32_t *bufptr; + + span_log(&s->logging, SPAN_LOG_FLOW, "Start rx page - compression %d\n", s->line_encoding); + if (s->tiff.tiff_file == NULL) + return -1; + + /* Calculate the scanline/tile width. */ + bytes_per_row = (s->image_width + 7)/8; + run_space = (s->image_width + 4)*sizeof(uint32_t); + if (bytes_per_row != s->bytes_per_row) + { + /* Allocate the space required for decoding the new row length. */ + s->bytes_per_row = bytes_per_row; + if ((bufptr = (uint32_t *) realloc(s->cur_runs, run_space)) == NULL) + return -1; + s->cur_runs = bufptr; + if ((bufptr = (uint32_t *) realloc(s->ref_runs, run_space)) == NULL) + return -1; + s->ref_runs = bufptr; + } + memset(s->cur_runs, 0, run_space); + memset(s->ref_runs, 0, run_space); + + s->t4_t6_rx.rx_bits = 0; + s->t4_t6_rx.rx_skip_bits = 0; + s->t4_t6_rx.rx_bitstream = 0; + s->row_bits = 0; + s->min_row_bits = INT_MAX; + s->max_row_bits = 0; + + s->row_is_2d = (s->line_encoding == T4_COMPRESSION_ITU_T6); + /* We start at -1 EOLs for 1D and 2D decoding, as an indication we are waiting for the + first EOL. T.6 coding starts without any preamble. */ + s->t4_t6_rx.consecutive_eols = (s->line_encoding == T4_COMPRESSION_ITU_T6) ? 0 : -1; + + s->t4_t6_rx.bad_rows = 0; + s->t4_t6_rx.longest_bad_row_run = 0; + s->t4_t6_rx.curr_bad_row_run = 0; + s->image_length = 0; + s->tx_bitstream = 0; + s->tx_bits = 8; + s->image_size = 0; + s->line_image_size = 0; + s->t4_t6_rx.last_row_starts_at = 0; + + s->row_len = 0; + s->t4_t6_rx.its_black = FALSE; + s->t4_t6_rx.black_white = 0; + + /* Initialise the reference line to all white */ + s->ref_runs[0] = + s->ref_runs[1] = + s->ref_runs[2] = + s->ref_runs[3] = s->image_width; + + s->t4_t6_rx.b_cursor = 1; + s->t4_t6_rx.a_cursor = 0; + s->t4_t6_rx.b1 = s->ref_runs[0]; + s->t4_t6_rx.a0 = 0; + + s->t4_t6_rx.run_length = 0; + + time (&s->page_start_time); + + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_rx_release(t4_state_t *s) +{ + if (!s->rx) + return -1; + if (s->tiff.tiff_file) + close_tiff_output_file(s); + free_buffers(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_rx_free(t4_state_t *s) +{ + int ret; + + ret = t4_rx_release(s); + free(s); + return ret; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_rx_set_rx_encoding(t4_state_t *s, int encoding) +{ + s->line_encoding = encoding; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_rx_set_image_width(t4_state_t *s, int width) +{ + s->image_width = width; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_rx_set_y_resolution(t4_state_t *s, int resolution) +{ + s->y_resolution = resolution; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_rx_set_x_resolution(t4_state_t *s, int resolution) +{ + s->x_resolution = resolution; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_rx_set_dcs(t4_state_t *s, const char *dcs) +{ + s->tiff.dcs = (dcs && dcs[0]) ? dcs : NULL; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_rx_set_sub_address(t4_state_t *s, const char *sub_address) +{ + s->tiff.sub_address = (sub_address && sub_address[0]) ? sub_address : NULL; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_rx_set_far_ident(t4_state_t *s, const char *ident) +{ + s->tiff.far_ident = (ident && ident[0]) ? ident : NULL; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_rx_set_vendor(t4_state_t *s, const char *vendor) +{ + s->tiff.vendor = vendor; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_rx_set_model(t4_state_t *s, const char *model) +{ + s->tiff.model = model; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_get_transfer_statistics(t4_state_t *s, t4_stats_t *t) +{ + t->pages_transferred = s->current_page - s->tiff.start_page; + t->pages_in_file = s->tiff.pages_in_file; + t->width = s->image_width; + t->length = s->image_length; + t->bad_rows = s->t4_t6_rx.bad_rows; + t->longest_bad_row_run = s->t4_t6_rx.longest_bad_row_run; + t->x_resolution = s->x_resolution; + t->y_resolution = s->y_resolution; + t->encoding = s->line_encoding; + t->line_image_size = s->line_image_size/8; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(const char *) t4_encoding_to_str(int encoding) +{ + switch (encoding) + { + case T4_COMPRESSION_ITU_T4_1D: + return "T.4 1-D"; + case T4_COMPRESSION_ITU_T4_2D: + return "T.4 2-D"; + case T4_COMPRESSION_ITU_T6: + return "T.6"; + } + return "???"; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_t6_decode_states.h b/libs/spandsp/src/t4_t6_decode_states.h new file mode 100644 index 0000000000..71619e5d6a --- /dev/null +++ b/libs/spandsp/src/t4_t6_decode_states.h @@ -0,0 +1,12486 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * t4_t6_decode_states.h - state tables for T.4/T.6 FAX image decoding + * + * Written by Steve Underwood + * + * Copyright (C) 2004 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: t4_t6_decode_states.h,v 1.1.2.4 2009/12/19 10:21:43 steveu Exp $ + */ + +/* Legitimate runs of zero bits which are the tail end of one code + plus the start of the next code do not exceed 10 bits. */ + +/* Finite state machine state codes */ +enum +{ + S_Null = 0, + S_Pass = 1, + S_Horiz = 2, + S_Vert = 3, + S_Ext = 4, + S_TermW = 5, + S_TermB = 6, + S_MakeUpW = 7, + S_MakeUpB = 8, + S_MakeUp = 9, + S_EOL = 10 +}; + +/*! T.4 finite state machine state table entry */ +typedef struct +{ + /*! State */ + uint8_t state; + /*! Width of code in bits */ + uint8_t width; + /*! Run length in bits */ + int16_t param; +} t4_table_entry_t; + +static const t4_table_entry_t t4_2d_table[128] = +{ + {S_Null, 1, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Pass, 4, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Vert, 6, -2}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Pass, 4, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Vert, 7, -3}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Pass, 4, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Vert, 6, 2}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Pass, 4, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Ext, 7, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Pass, 4, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Vert, 6, -2}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Pass, 4, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Vert, 7, 3}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Pass, 4, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Vert, 6, 2}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0}, + {S_Pass, 4, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, -1}, + {S_Vert, 1, 0}, + {S_Horiz, 3, 0}, + {S_Vert, 1, 0}, + {S_Vert, 3, 1}, + {S_Vert, 1, 0} +}; + +static const t4_table_entry_t t4_1d_white_table[4096] = +{ + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1472}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1216}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 960}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 704}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 11, 1792}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 832}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1600}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1344}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1088}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1536}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1280}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1024}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 768}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 11, 1856}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 896}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1728}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1408}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1152}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1472}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1216}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 960}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 704}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 2112}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 832}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1600}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1344}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1088}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1536}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1280}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1024}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 768}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 2368}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 896}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1728}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1408}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1152}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1472}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1216}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 960}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 704}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 1984}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 832}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1600}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1344}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1088}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1536}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1280}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1024}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 768}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 11, 1920}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 896}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1728}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1408}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1152}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1472}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1216}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 960}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 704}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 2240}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 832}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1600}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1344}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1088}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1536}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1280}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1024}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 768}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 2496}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 896}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1728}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1408}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1152}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_EOL, 12, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1472}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1216}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 960}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 704}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 11, 1792}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 832}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1600}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1344}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1088}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1536}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1280}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1024}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 768}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 11, 1856}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 896}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1728}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1408}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1152}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1472}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1216}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 960}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 704}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 2176}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 832}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1600}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1344}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1088}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1536}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1280}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1024}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 768}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 2432}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 896}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1728}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1408}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1152}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1472}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1216}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 960}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 704}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 2048}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 832}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1600}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1344}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1088}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1536}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1280}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1024}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 768}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 11, 1920}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 896}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1728}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1408}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1152}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1472}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1216}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 960}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 704}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 2304}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 832}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1600}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1344}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1088}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_Null, 1, 0}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 39}, + {S_TermW, 6, 16}, + {S_MakeUpW, 8, 576}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 55}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 45}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 53}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 448}, + {S_TermW, 4, 6}, + {S_TermW, 8, 35}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 51}, + {S_TermW, 6, 15}, + {S_TermW, 8, 63}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1536}, + {S_TermW, 4, 5}, + {S_TermW, 8, 43}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1280}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 29}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 33}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 49}, + {S_TermW, 6, 14}, + {S_TermW, 8, 61}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 47}, + {S_TermW, 4, 3}, + {S_TermW, 8, 59}, + {S_TermW, 4, 5}, + {S_TermW, 8, 41}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1024}, + {S_TermW, 4, 6}, + {S_TermW, 8, 31}, + {S_TermW, 5, 8}, + {S_TermW, 8, 57}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 9, 768}, + {S_TermW, 4, 6}, + {S_TermW, 8, 37}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 320}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_MakeUp, 12, 2560}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 7, 20}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 24}, + {S_TermW, 6, 14}, + {S_TermW, 7, 28}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 23}, + {S_TermW, 4, 3}, + {S_TermW, 7, 27}, + {S_TermW, 4, 5}, + {S_TermW, 8, 40}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 896}, + {S_TermW, 4, 6}, + {S_TermW, 7, 19}, + {S_TermW, 5, 8}, + {S_TermW, 8, 56}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 46}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 8, 54}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 512}, + {S_TermW, 4, 6}, + {S_TermW, 8, 36}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 52}, + {S_TermW, 6, 15}, + {S_TermW, 8, 0}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_MakeUpW, 9, 1728}, + {S_TermW, 4, 5}, + {S_TermW, 8, 44}, + {S_TermW, 6, 17}, + {S_MakeUpW, 9, 1408}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 30}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 6, 12}, + {S_TermW, 5, 9}, + {S_MakeUpW, 6, 1664}, + {S_TermW, 4, 6}, + {S_TermW, 8, 34}, + {S_MakeUpW, 5, 128}, + {S_TermW, 8, 50}, + {S_TermW, 6, 14}, + {S_TermW, 8, 62}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 8, 48}, + {S_TermW, 4, 3}, + {S_TermW, 8, 60}, + {S_TermW, 4, 5}, + {S_TermW, 8, 42}, + {S_TermW, 6, 16}, + {S_MakeUpW, 9, 1152}, + {S_TermW, 4, 6}, + {S_TermW, 8, 32}, + {S_TermW, 5, 8}, + {S_TermW, 8, 58}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 7, 22}, + {S_TermW, 4, 3}, + {S_TermW, 5, 11}, + {S_TermW, 4, 5}, + {S_TermW, 7, 26}, + {S_TermW, 5, 9}, + {S_MakeUpW, 8, 640}, + {S_TermW, 4, 6}, + {S_TermW, 8, 38}, + {S_MakeUpW, 5, 128}, + {S_TermW, 7, 25}, + {S_TermW, 6, 15}, + {S_MakeUpW, 8, 384}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7}, + {S_TermW, 6, 13}, + {S_TermW, 4, 3}, + {S_TermW, 7, 18}, + {S_TermW, 4, 5}, + {S_TermW, 7, 21}, + {S_TermW, 6, 17}, + {S_MakeUpW, 7, 256}, + {S_TermW, 4, 6}, + {S_TermW, 6, 1}, + {S_TermW, 5, 8}, + {S_MakeUpW, 6, 192}, + {S_MakeUpW, 5, 64}, + {S_TermW, 5, 10}, + {S_TermW, 4, 4}, + {S_TermW, 4, 2}, + {S_TermW, 4, 7} +}; + +static const t4_table_entry_t t4_1d_black_table[8192] = +{ + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 18}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 17}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1792}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 23}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 20}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 25}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 128}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 56}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 30}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1856}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 57}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 21}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 54}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 52}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 48}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2112}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 44}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 36}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 384}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 28}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 60}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 40}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2368}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 16}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 10, 64}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 18}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 17}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 1984}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 50}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 34}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1664}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 26}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1408}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 32}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1920}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 61}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 42}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1024}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 768}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 62}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2240}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 46}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 38}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 512}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 19}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 24}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 22}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2496}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 16}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 10, 64}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_EOL, 12, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 18}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 17}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1792}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 23}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 20}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 25}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 192}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1280}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 31}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1856}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 58}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 21}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 896}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 640}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 49}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2176}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 45}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 37}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 448}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 29}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1536}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 41}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2432}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 16}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 10, 64}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 18}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 17}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2048}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 51}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 35}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 320}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 27}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 59}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 33}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1920}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 256}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 43}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1152}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 55}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 63}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2304}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 47}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 39}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 53}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 19}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 24}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 22}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2560}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 16}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 10, 64}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 18}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 17}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1792}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 23}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 20}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 25}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 128}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 56}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 30}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1856}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 57}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 21}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 54}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 52}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 48}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2112}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 44}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 36}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 384}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 28}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 60}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 40}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2368}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 16}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 10, 64}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 18}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 17}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 1984}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 50}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 34}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1728}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 26}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1472}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 32}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1920}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 61}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 42}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1088}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 832}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 62}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2240}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 46}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 38}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 576}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 19}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 24}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 22}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2496}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 16}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 10, 64}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_EOL, 12, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 18}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 17}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1792}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 23}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 20}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 25}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 192}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1344}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 31}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1856}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 58}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 21}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 960}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 704}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 49}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2176}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 45}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 37}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 448}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 29}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1600}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 41}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2432}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 16}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 10, 64}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 18}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 17}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2048}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 51}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 35}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 320}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 27}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 59}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 33}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 11, 1920}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 12, 256}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 43}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 13, 1216}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 9, 15}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 55}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 63}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2304}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 47}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 39}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 12, 53}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_Null, 1, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 13}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 19}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 24}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 11, 22}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUp, 12, 2560}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 10}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 16}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 10, 0}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_MakeUpB, 10, 64}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 9}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 11}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 8, 14}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 6, 8}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 7, 12}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 6}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2}, + {S_TermB, 5, 7}, + {S_TermB, 2, 3}, + {S_TermB, 3, 1}, + {S_TermB, 2, 2}, + {S_TermB, 4, 5}, + {S_TermB, 2, 3}, + {S_TermB, 3, 4}, + {S_TermB, 2, 2} +}; + +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c new file mode 100644 index 0000000000..4efb3ad449 --- /dev/null +++ b/libs/spandsp/src/t4_tx.c @@ -0,0 +1,1539 @@ +//#define T4_STATE_DEBUGGING +/* + * SpanDSP - a series of DSP components for telephony + * + * t4_tx.c - ITU T.4 FAX transmit processing + * + * Written by Steve Underwood + * + * Copyright (C) 2003, 2007 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: t4_tx.c,v 1.13.2.9 2009/12/21 17:18:40 steveu Exp $ + */ + +/* + * Much of this file is based on the T.4 and T.6 support in libtiff, which requires + * the following notice in any derived source code: + * + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include "floating_fudge.h" +#include + +#include "spandsp/telephony.h" +#include "spandsp/logging.h" +#include "spandsp/bit_operations.h" +#include "spandsp/async.h" +#include "spandsp/t4_rx.h" +#include "spandsp/t4_tx.h" +#include "spandsp/version.h" + +#include "spandsp/private/logging.h" +#include "spandsp/private/t4_rx.h" +#include "spandsp/private/t4_tx.h" + +/*! The number of centimetres in one inch */ +#define CM_PER_INCH 2.54f + +/*! The number of EOLs to be sent at the end of a T.4 page */ +#define EOLS_TO_END_T4_TX_PAGE 6 +/*! The number of EOLs to be sent at the end of a T.6 page */ +#define EOLS_TO_END_T6_TX_PAGE 2 + +#if defined(T4_STATE_DEBUGGING) +static void STATE_TRACE(const char *format, ...) +{ + va_list arg_ptr; + + va_start(arg_ptr, format); + vprintf(format, arg_ptr); + va_end(arg_ptr); +} +/*- End of function --------------------------------------------------------*/ +#else +#define STATE_TRACE(...) /**/ +#endif + +/*! T.4 run length table entry */ +typedef struct +{ + /*! Length of T.4 code, in bits */ + uint16_t length; + /*! T.4 code */ + uint16_t code; + /*! Run length, in bits */ + int16_t run_length; +} t4_run_table_entry_t; + +#include "faxfont.h" + +/* Legitimate runs of zero bits which are the tail end of one code + plus the start of the next code do not exceed 10 bits. */ + +/* + * Note that these tables are ordered such that the index into the table + * is known to be either the run length, or (run length / 64) + a fixed + * offset. + */ +static const t4_run_table_entry_t t4_white_codes[] = +{ + { 8, 0x00AC, 0}, /* 0011 0101 */ + { 6, 0x0038, 1}, /* 0001 11 */ + { 4, 0x000E, 2}, /* 0111 */ + { 4, 0x0001, 3}, /* 1000 */ + { 4, 0x000D, 4}, /* 1011 */ + { 4, 0x0003, 5}, /* 1100 */ + { 4, 0x0007, 6}, /* 1110 */ + { 4, 0x000F, 7}, /* 1111 */ + { 5, 0x0019, 8}, /* 1001 1 */ + { 5, 0x0005, 9}, /* 1010 0 */ + { 5, 0x001C, 10}, /* 0011 1 */ + { 5, 0x0002, 11}, /* 0100 0 */ + { 6, 0x0004, 12}, /* 0010 00 */ + { 6, 0x0030, 13}, /* 0000 11 */ + { 6, 0x000B, 14}, /* 1101 00 */ + { 6, 0x002B, 15}, /* 1101 01 */ + { 6, 0x0015, 16}, /* 1010 10 */ + { 6, 0x0035, 17}, /* 1010 11 */ + { 7, 0x0072, 18}, /* 0100 111 */ + { 7, 0x0018, 19}, /* 0001 100 */ + { 7, 0x0008, 20}, /* 0001 000 */ + { 7, 0x0074, 21}, /* 0010 111 */ + { 7, 0x0060, 22}, /* 0000 011 */ + { 7, 0x0010, 23}, /* 0000 100 */ + { 7, 0x000A, 24}, /* 0101 000 */ + { 7, 0x006A, 25}, /* 0101 011 */ + { 7, 0x0064, 26}, /* 0010 011 */ + { 7, 0x0012, 27}, /* 0100 100 */ + { 7, 0x000C, 28}, /* 0011 000 */ + { 8, 0x0040, 29}, /* 0000 0010 */ + { 8, 0x00C0, 30}, /* 0000 0011 */ + { 8, 0x0058, 31}, /* 0001 1010 */ + { 8, 0x00D8, 32}, /* 0001 1011 */ + { 8, 0x0048, 33}, /* 0001 0010 */ + { 8, 0x00C8, 34}, /* 0001 0011 */ + { 8, 0x0028, 35}, /* 0001 0100 */ + { 8, 0x00A8, 36}, /* 0001 0101 */ + { 8, 0x0068, 37}, /* 0001 0110 */ + { 8, 0x00E8, 38}, /* 0001 0111 */ + { 8, 0x0014, 39}, /* 0010 1000 */ + { 8, 0x0094, 40}, /* 0010 1001 */ + { 8, 0x0054, 41}, /* 0010 1010 */ + { 8, 0x00D4, 42}, /* 0010 1011 */ + { 8, 0x0034, 43}, /* 0010 1100 */ + { 8, 0x00B4, 44}, /* 0010 1101 */ + { 8, 0x0020, 45}, /* 0000 0100 */ + { 8, 0x00A0, 46}, /* 0000 0101 */ + { 8, 0x0050, 47}, /* 0000 1010 */ + { 8, 0x00D0, 48}, /* 0000 1011 */ + { 8, 0x004A, 49}, /* 0101 0010 */ + { 8, 0x00CA, 50}, /* 0101 0011 */ + { 8, 0x002A, 51}, /* 0101 0100 */ + { 8, 0x00AA, 52}, /* 0101 0101 */ + { 8, 0x0024, 53}, /* 0010 0100 */ + { 8, 0x00A4, 54}, /* 0010 0101 */ + { 8, 0x001A, 55}, /* 0101 1000 */ + { 8, 0x009A, 56}, /* 0101 1001 */ + { 8, 0x005A, 57}, /* 0101 1010 */ + { 8, 0x00DA, 58}, /* 0101 1011 */ + { 8, 0x0052, 59}, /* 0100 1010 */ + { 8, 0x00D2, 60}, /* 0100 1011 */ + { 8, 0x004C, 61}, /* 0011 0010 */ + { 8, 0x00CC, 62}, /* 0011 0011 */ + { 8, 0x002C, 63}, /* 0011 0100 */ + { 5, 0x001B, 64}, /* 1101 1 */ + { 5, 0x0009, 128}, /* 1001 0 */ + { 6, 0x003A, 192}, /* 0101 11 */ + { 7, 0x0076, 256}, /* 0110 111 */ + { 8, 0x006C, 320}, /* 0011 0110 */ + { 8, 0x00EC, 384}, /* 0011 0111 */ + { 8, 0x0026, 448}, /* 0110 0100 */ + { 8, 0x00A6, 512}, /* 0110 0101 */ + { 8, 0x0016, 576}, /* 0110 1000 */ + { 8, 0x00E6, 640}, /* 0110 0111 */ + { 9, 0x0066, 704}, /* 0110 0110 0 */ + { 9, 0x0166, 768}, /* 0110 0110 1 */ + { 9, 0x0096, 832}, /* 0110 1001 0 */ + { 9, 0x0196, 896}, /* 0110 1001 1 */ + { 9, 0x0056, 960}, /* 0110 1010 0 */ + { 9, 0x0156, 1024}, /* 0110 1010 1 */ + { 9, 0x00D6, 1088}, /* 0110 1011 0 */ + { 9, 0x01D6, 1152}, /* 0110 1011 1 */ + { 9, 0x0036, 1216}, /* 0110 1100 0 */ + { 9, 0x0136, 1280}, /* 0110 1100 1 */ + { 9, 0x00B6, 1344}, /* 0110 1101 0 */ + { 9, 0x01B6, 1408}, /* 0110 1101 1 */ + { 9, 0x0032, 1472}, /* 0100 1100 0 */ + { 9, 0x0132, 1536}, /* 0100 1100 1 */ + { 9, 0x00B2, 1600}, /* 0100 1101 0 */ + { 6, 0x0006, 1664}, /* 0110 00 */ + { 9, 0x01B2, 1728}, /* 0100 1101 1 */ + {11, 0x0080, 1792}, /* 0000 0001 000 */ + {11, 0x0180, 1856}, /* 0000 0001 100 */ + {11, 0x0580, 1920}, /* 0000 0001 101 */ + {12, 0x0480, 1984}, /* 0000 0001 0010 */ + {12, 0x0C80, 2048}, /* 0000 0001 0011 */ + {12, 0x0280, 2112}, /* 0000 0001 0100 */ + {12, 0x0A80, 2176}, /* 0000 0001 0101 */ + {12, 0x0680, 2240}, /* 0000 0001 0110 */ + {12, 0x0E80, 2304}, /* 0000 0001 0111 */ + {12, 0x0380, 2368}, /* 0000 0001 1100 */ + {12, 0x0B80, 2432}, /* 0000 0001 1101 */ + {12, 0x0780, 2496}, /* 0000 0001 1110 */ + {12, 0x0F80, 2560}, /* 0000 0001 1111 */ +}; + +static const t4_run_table_entry_t t4_black_codes[] = +{ + {10, 0x03B0, 0}, /* 0000 1101 11 */ + { 3, 0x0002, 1}, /* 010 */ + { 2, 0x0003, 2}, /* 11 */ + { 2, 0x0001, 3}, /* 10 */ + { 3, 0x0006, 4}, /* 011 */ + { 4, 0x000C, 5}, /* 0011 */ + { 4, 0x0004, 6}, /* 0010 */ + { 5, 0x0018, 7}, /* 0001 1 */ + { 6, 0x0028, 8}, /* 0001 01 */ + { 6, 0x0008, 9}, /* 0001 00 */ + { 7, 0x0010, 10}, /* 0000 100 */ + { 7, 0x0050, 11}, /* 0000 101 */ + { 7, 0x0070, 12}, /* 0000 111 */ + { 8, 0x0020, 13}, /* 0000 0100 */ + { 8, 0x00E0, 14}, /* 0000 0111 */ + { 9, 0x0030, 15}, /* 0000 1100 0 */ + {10, 0x03A0, 16}, /* 0000 0101 11 */ + {10, 0x0060, 17}, /* 0000 0110 00 */ + {10, 0x0040, 18}, /* 0000 0010 00 */ + {11, 0x0730, 19}, /* 0000 1100 111 */ + {11, 0x00B0, 20}, /* 0000 1101 000 */ + {11, 0x01B0, 21}, /* 0000 1101 100 */ + {11, 0x0760, 22}, /* 0000 0110 111 */ + {11, 0x00A0, 23}, /* 0000 0101 000 */ + {11, 0x0740, 24}, /* 0000 0010 111 */ + {11, 0x00C0, 25}, /* 0000 0011 000 */ + {12, 0x0530, 26}, /* 0000 1100 1010 */ + {12, 0x0D30, 27}, /* 0000 1100 1011 */ + {12, 0x0330, 28}, /* 0000 1100 1100 */ + {12, 0x0B30, 29}, /* 0000 1100 1101 */ + {12, 0x0160, 30}, /* 0000 0110 1000 */ + {12, 0x0960, 31}, /* 0000 0110 1001 */ + {12, 0x0560, 32}, /* 0000 0110 1010 */ + {12, 0x0D60, 33}, /* 0000 0110 1011 */ + {12, 0x04B0, 34}, /* 0000 1101 0010 */ + {12, 0x0CB0, 35}, /* 0000 1101 0011 */ + {12, 0x02B0, 36}, /* 0000 1101 0100 */ + {12, 0x0AB0, 37}, /* 0000 1101 0101 */ + {12, 0x06B0, 38}, /* 0000 1101 0110 */ + {12, 0x0EB0, 39}, /* 0000 1101 0111 */ + {12, 0x0360, 40}, /* 0000 0110 1100 */ + {12, 0x0B60, 41}, /* 0000 0110 1101 */ + {12, 0x05B0, 42}, /* 0000 1101 1010 */ + {12, 0x0DB0, 43}, /* 0000 1101 1011 */ + {12, 0x02A0, 44}, /* 0000 0101 0100 */ + {12, 0x0AA0, 45}, /* 0000 0101 0101 */ + {12, 0x06A0, 46}, /* 0000 0101 0110 */ + {12, 0x0EA0, 47}, /* 0000 0101 0111 */ + {12, 0x0260, 48}, /* 0000 0110 0100 */ + {12, 0x0A60, 49}, /* 0000 0110 0101 */ + {12, 0x04A0, 50}, /* 0000 0101 0010 */ + {12, 0x0CA0, 51}, /* 0000 0101 0011 */ + {12, 0x0240, 52}, /* 0000 0010 0100 */ + {12, 0x0EC0, 53}, /* 0000 0011 0111 */ + {12, 0x01C0, 54}, /* 0000 0011 1000 */ + {12, 0x0E40, 55}, /* 0000 0010 0111 */ + {12, 0x0140, 56}, /* 0000 0010 1000 */ + {12, 0x01A0, 57}, /* 0000 0101 1000 */ + {12, 0x09A0, 58}, /* 0000 0101 1001 */ + {12, 0x0D40, 59}, /* 0000 0010 1011 */ + {12, 0x0340, 60}, /* 0000 0010 1100 */ + {12, 0x05A0, 61}, /* 0000 0101 1010 */ + {12, 0x0660, 62}, /* 0000 0110 0110 */ + {12, 0x0E60, 63}, /* 0000 0110 0111 */ + {10, 0x03C0, 64}, /* 0000 0011 11 */ + {12, 0x0130, 128}, /* 0000 1100 1000 */ + {12, 0x0930, 192}, /* 0000 1100 1001 */ + {12, 0x0DA0, 256}, /* 0000 0101 1011 */ + {12, 0x0CC0, 320}, /* 0000 0011 0011 */ + {12, 0x02C0, 384}, /* 0000 0011 0100 */ + {12, 0x0AC0, 448}, /* 0000 0011 0101 */ + {13, 0x06C0, 512}, /* 0000 0011 0110 0 */ + {13, 0x16C0, 576}, /* 0000 0011 0110 1 */ + {13, 0x0A40, 640}, /* 0000 0010 0101 0 */ + {13, 0x1A40, 704}, /* 0000 0010 0101 1 */ + {13, 0x0640, 768}, /* 0000 0010 0110 0 */ + {13, 0x1640, 832}, /* 0000 0010 0110 1 */ + {13, 0x09C0, 896}, /* 0000 0011 1001 0 */ + {13, 0x19C0, 960}, /* 0000 0011 1001 1 */ + {13, 0x05C0, 1024}, /* 0000 0011 1010 0 */ + {13, 0x15C0, 1088}, /* 0000 0011 1010 1 */ + {13, 0x0DC0, 1152}, /* 0000 0011 1011 0 */ + {13, 0x1DC0, 1216}, /* 0000 0011 1011 1 */ + {13, 0x0940, 1280}, /* 0000 0010 1001 0 */ + {13, 0x1940, 1344}, /* 0000 0010 1001 1 */ + {13, 0x0540, 1408}, /* 0000 0010 1010 0 */ + {13, 0x1540, 1472}, /* 0000 0010 1010 1 */ + {13, 0x0B40, 1536}, /* 0000 0010 1101 0 */ + {13, 0x1B40, 1600}, /* 0000 0010 1101 1 */ + {13, 0x04C0, 1664}, /* 0000 0011 0010 0 */ + {13, 0x14C0, 1728}, /* 0000 0011 0010 1 */ + {11, 0x0080, 1792}, /* 0000 0001 000 */ + {11, 0x0180, 1856}, /* 0000 0001 100 */ + {11, 0x0580, 1920}, /* 0000 0001 101 */ + {12, 0x0480, 1984}, /* 0000 0001 0010 */ + {12, 0x0C80, 2048}, /* 0000 0001 0011 */ + {12, 0x0280, 2112}, /* 0000 0001 0100 */ + {12, 0x0A80, 2176}, /* 0000 0001 0101 */ + {12, 0x0680, 2240}, /* 0000 0001 0110 */ + {12, 0x0E80, 2304}, /* 0000 0001 0111 */ + {12, 0x0380, 2368}, /* 0000 0001 1100 */ + {12, 0x0B80, 2432}, /* 0000 0001 1101 */ + {12, 0x0780, 2496}, /* 0000 0001 1110 */ + {12, 0x0F80, 2560}, /* 0000 0001 1111 */ +}; + +static int encode_row(t4_state_t *s); + +static void make_header(t4_state_t *s, char *header) +{ + time_t now; + struct tm tm; + static const char *months[] = + { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + time(&now); + tm = *localtime(&now); + snprintf(header, + 132, + " %2d-%s-%d %02d:%02d %-50s %-21s p.%d", + tm.tm_mday, + months[tm.tm_mon], + tm.tm_year + 1900, + tm.tm_hour, + tm.tm_min, + s->t4_t6_tx.header_info, + s->tiff.local_ident, + s->current_page + 1); +} +/*- End of function --------------------------------------------------------*/ + +static int t4_tx_put_fax_header(t4_state_t *s) +{ + int row; + int i; + int repeats; + int pattern; + int row_bufptr; + char *t; + char header[132 + 1]; + + /* Modify the resulting image to include a header line, typical of hardware FAX machines */ + make_header(s, header); + switch (s->y_resolution) + { + case T4_Y_RESOLUTION_1200: + repeats = 12; + break; + case T4_Y_RESOLUTION_800: + repeats = 8; + break; + case T4_Y_RESOLUTION_600: + repeats = 6; + break; + case T4_Y_RESOLUTION_SUPERFINE: + repeats = 4; + break; + case T4_Y_RESOLUTION_300: + repeats = 3; + break; + case T4_Y_RESOLUTION_FINE: + repeats = 2; + break; + default: + repeats = 1; + break; + } + for (row = 0; row < 16; row++) + { + t = header; + row_bufptr = 0; + for (t = header; *t && row_bufptr <= s->bytes_per_row - 2; t++) + { + pattern = header_font[(uint8_t) *t][row]; + s->row_buf[row_bufptr++] = (uint8_t) (pattern >> 8); + s->row_buf[row_bufptr++] = (uint8_t) (pattern & 0xFF); + } + for ( ; row_bufptr < s->bytes_per_row; ) + s->row_buf[row_bufptr++] = 0; + for (i = 0; i < repeats; i++) + { + if (encode_row(s)) + return -1; + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int test_resolution(int res_unit, float actual, float expected) +{ + if (res_unit == RESUNIT_INCH) + actual *= 1.0f/CM_PER_INCH; + return (expected*0.95f <= actual && actual <= expected*1.05f); +} +/*- End of function --------------------------------------------------------*/ + +static int get_tiff_directory_info(t4_state_t *s) +{ + static const struct + { + float resolution; + int code; + } x_res_table[] = + { + { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, + { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, + { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, + { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, + { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, + { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, + {1200.0f/CM_PER_INCH, T4_X_RESOLUTION_1200}, + { -1.00f, -1} + }; + static const struct + { + float resolution; + int code; + int max_rows_to_next_1d_row; + } y_res_table[] = + { + { 38.50f, T4_Y_RESOLUTION_STANDARD, 2}, + { 77.00f, T4_Y_RESOLUTION_FINE, 4}, + { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300, 6}, + { 154.00f, T4_Y_RESOLUTION_SUPERFINE, 8}, + { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600, 12}, + { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800, 16}, + {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200, 24}, + { -1.00f, -1, -1} + }; + uint16_t res_unit; + uint16_t parm16; + uint32_t parm32; + float x_resolution; + float y_resolution; + int i; + t4_tiff_state_t *t; + + t = &s->tiff; + parm16 = 0; + TIFFGetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, &parm16); + if (parm16 != 1) + return -1; + TIFFGetField(t->tiff_file, TIFFTAG_SAMPLESPERPIXEL, &parm16); + if (parm16 != 1) + return -1; + parm32 = 0; + TIFFGetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, &parm32); + s->image_width = parm32; + s->bytes_per_row = (s->image_width + 7)/8; + parm32 = 0; + TIFFGetField(t->tiff_file, TIFFTAG_IMAGELENGTH, &parm32); + s->image_length = parm32; + x_resolution = 0.0f; + TIFFGetField(t->tiff_file, TIFFTAG_XRESOLUTION, &x_resolution); + y_resolution = 0.0f; + TIFFGetField(t->tiff_file, TIFFTAG_YRESOLUTION, &y_resolution); + res_unit = RESUNIT_INCH; + TIFFGetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); + t->photo_metric = PHOTOMETRIC_MINISWHITE; + TIFFGetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, &t->photo_metric); + if (t->photo_metric != PHOTOMETRIC_MINISWHITE) + span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", t->file); + t->fill_order = FILLORDER_LSB2MSB; +#if 0 + TIFFGetField(t->tiff_file, TIFFTAG_FILLORDER, &t->fill_order); + if (t->fill_order != FILLORDER_LSB2MSB) + span_log(&s->logging, SPAN_LOG_FLOW, "%s: Fill order needs swapping.\n", t->file); +#endif + + /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the + precise value. The other value should be exact. */ + /* Treat everything we can't match as R8. Most FAXes are this resolution anyway. */ + s->x_resolution = T4_X_RESOLUTION_R8; + for (i = 0; x_res_table[i].code > 0; i++) + { + if (test_resolution(res_unit, x_resolution, x_res_table[i].resolution)) + { + s->x_resolution = x_res_table[i].code; + break; + } + } + + s->y_resolution = T4_Y_RESOLUTION_STANDARD; + s->t4_t6_tx.max_rows_to_next_1d_row = 2; + for (i = 0; y_res_table[i].code > 0; i++) + { + if (test_resolution(res_unit, y_resolution, y_res_table[i].resolution)) + { + s->y_resolution = y_res_table[i].code; + s->t4_t6_tx.max_rows_to_next_1d_row = y_res_table[i].max_rows_to_next_1d_row; + break; + } + } + + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int test_tiff_directory_info(t4_state_t *s) +{ + static const struct + { + float resolution; + int code; + } x_res_table[] = + { + { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, + { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, + { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, + { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, + { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, + { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, + {1200.0f/CM_PER_INCH, T4_X_RESOLUTION_1200}, + { -1.00f, -1} + }; + static const struct + { + float resolution; + int code; + int max_rows_to_next_1d_row; + } y_res_table[] = + { + { 38.50f, T4_Y_RESOLUTION_STANDARD, 2}, + { 77.00f, T4_Y_RESOLUTION_FINE, 4}, + { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300, 6}, + { 154.00f, T4_Y_RESOLUTION_SUPERFINE, 8}, + { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600, 12}, + { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800, 16}, + {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200, 24}, + { -1.00f, -1, -1} + }; + uint16_t res_unit; + uint16_t parm16; + uint32_t parm32; + float x_resolution; + float y_resolution; + int i; + t4_tiff_state_t *t; + + t = &s->tiff; + parm16 = 0; + TIFFGetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, &parm16); + if (parm16 != 1) + return -1; + parm32 = 0; + TIFFGetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, &parm32); + if (s->image_width != (int) parm32) + return 1; + x_resolution = 0.0f; + TIFFGetField(t->tiff_file, TIFFTAG_XRESOLUTION, &x_resolution); + y_resolution = 0.0f; + TIFFGetField(t->tiff_file, TIFFTAG_YRESOLUTION, &y_resolution); + res_unit = RESUNIT_INCH; + TIFFGetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); + + /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the + precise value. The other value should be exact. */ + /* Treat everything we can't match as R8. Most FAXes are this resolution anyway. */ + for (i = 0; x_res_table[i].code > 0; i++) + { + if (test_resolution(res_unit, x_resolution, x_res_table[i].resolution)) + break; + } + if (s->x_resolution != x_res_table[i].code) + return 1; + for (i = 0; y_res_table[i].code > 0; i++) + { + if (test_resolution(res_unit, y_resolution, y_res_table[i].resolution)) + break; + } + if (s->y_resolution != y_res_table[i].code) + return 1; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int get_tiff_total_pages(t4_state_t *s) +{ + int max; + + /* Each page *should* contain the total number of pages, but can this be + trusted? Some files say 0. Actually searching for the last page is + more reliable. */ + max = 0; + while (TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) max)) + max++; + /* Back to the previous page */ + if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page)) + return -1; + return max; +} +/*- End of function --------------------------------------------------------*/ + +static int open_tiff_input_file(t4_state_t *s, const char *file) +{ + if ((s->tiff.tiff_file = TIFFOpen(file, "r")) == NULL) + return -1; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int read_tiff_image(t4_state_t *s) +{ + int row; + int image_length; + int i; + + image_length = 0; + TIFFGetField(s->tiff.tiff_file, TIFFTAG_IMAGELENGTH, &image_length); + for (row = 0; row < image_length; row++) + { + if (TIFFReadScanline(s->tiff.tiff_file, s->row_buf, row, 0) <= 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error at row %d.\n", s->tiff.file, row); + break; + } + if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE) + { + for (i = 0; i < s->bytes_per_row; i++) + s->row_buf[i] = ~s->row_buf[i]; + } + if (s->tiff.fill_order != FILLORDER_LSB2MSB) + bit_reverse(s->row_buf, s->row_buf, s->bytes_per_row); + if (encode_row(s)) + return -1; + } + return image_length; +} +/*- End of function --------------------------------------------------------*/ + +static int close_tiff_input_file(t4_state_t *s) +{ + TIFFClose(s->tiff.tiff_file); + s->tiff.tiff_file = NULL; + if (s->tiff.file) + free((char *) s->tiff.file); + s->tiff.file = NULL; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static void update_row_bit_info(t4_state_t *s) +{ + if (s->row_bits > s->max_row_bits) + s->max_row_bits = s->row_bits; + if (s->row_bits < s->min_row_bits) + s->min_row_bits = s->row_bits; + s->row_bits = 0; +} +/*- End of function --------------------------------------------------------*/ + +static int free_buffers(t4_state_t *s) +{ + if (s->image_buffer) + { + free(s->image_buffer); + s->image_buffer = NULL; + s->image_buffer_size = 0; + } + if (s->cur_runs) + { + free(s->cur_runs); + s->cur_runs = NULL; + } + if (s->ref_runs) + { + free(s->ref_runs); + s->ref_runs = NULL; + } + if (s->row_buf) + { + free(s->row_buf); + s->row_buf = NULL; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int row_to_run_lengths(uint32_t list[], const uint8_t row[], int width) +{ + uint32_t flip; + uint32_t x; + int span; + int entry; + int frag; + int rem; + int limit; + int i; + int pos; + + /* Deal with whole words first. We know we are starting on a word boundary. */ + entry = 0; + flip = 0; + limit = (width >> 3) & ~3; + span = 0; + pos = 0; + for (i = 0; i < limit; i += sizeof(uint32_t)) + { + x = *((uint32_t *) &row[i]); + if (x != flip) + { + x = ((uint32_t) row[i] << 24) | ((uint32_t) row[i + 1] << 16) | ((uint32_t) row[i + 2] << 8) | ((uint32_t) row[i + 3]); + /* We know we are going to find at least one transition. */ + frag = 31 - top_bit(x ^ flip); + pos += ((i << 3) - span + frag); + list[entry++] = pos; + x <<= frag; + flip ^= 0xFFFFFFFF; + rem = 32 - frag; + /* Now see if there are any more */ + while ((frag = 31 - top_bit(x ^ flip)) < rem) + { + pos += frag; + list[entry++] = pos; + x <<= frag; + flip ^= 0xFFFFFFFF; + rem -= frag; + } + /* Save the remainder of the word */ + span = (i << 3) + 32 - rem; + } + } + /* Now deal with some whole bytes, if there are any left. */ + limit = width >> 3; + flip &= 0xFF000000; + if (i < limit) + { + for ( ; i < limit; i++) + { + x = (uint32_t) row[i] << 24; + if (x != flip) + { + /* We know we are going to find at least one transition. */ + frag = 31 - top_bit(x ^ flip); + pos += ((i << 3) - span + frag); + list[entry++] = pos; + x <<= frag; + flip ^= 0xFF000000; + rem = 8 - frag; + /* Now see if there are any more */ + while ((frag = 31 - top_bit(x ^ flip)) < rem) + { + pos += frag; + list[entry++] = pos; + x <<= frag; + flip ^= 0xFF000000; + rem -= frag; + } + /* Save the remainder of the word */ + span = (i << 3) + 8 - rem; + } + } + } + /* Deal with any left over fractional byte. */ + span = (i << 3) - span; + if ((rem = width & 7)) + { + x = row[i]; + x <<= 24; + do + { + frag = 31 - top_bit(x ^ flip); + if (frag > rem) + frag = rem; + pos += (span + frag); + list[entry++] = pos; + x <<= frag; + span = 0; + flip ^= 0xFF000000; + rem -= frag; + } + while (rem > 0); + } + else + { + if (span) + { + pos += span; + list[entry++] = pos; + } + } + return entry; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int put_encoded_bits(t4_state_t *s, uint32_t bits, int length) +{ + uint8_t *t; + + /* We might be called with a large length value, to spew out a mass of zero bits for + minimum row length padding. */ + s->tx_bitstream |= (bits << s->tx_bits); + s->tx_bits += length; + s->row_bits += length; + if ((s->image_size + (s->tx_bits + 7)/8) >= s->image_buffer_size) + { + if ((t = realloc(s->image_buffer, s->image_buffer_size + 100*s->bytes_per_row)) == NULL) + return -1; + s->image_buffer = t; + s->image_buffer_size += 100*s->bytes_per_row; + } + while (s->tx_bits >= 8) + { + s->image_buffer[s->image_size++] = (uint8_t) (s->tx_bitstream & 0xFF); + s->tx_bitstream >>= 8; + s->tx_bits -= 8; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +/* + * Write the sequence of codes that describes + * the specified span of zero's or one's. The + * appropriate table that holds the make-up and + * terminating codes is supplied. + */ +static __inline__ int put_1d_span(t4_state_t *s, int32_t span, const t4_run_table_entry_t *tab) +{ + const t4_run_table_entry_t *te; + + te = &tab[63 + (2560 >> 6)]; + while (span >= 2560 + 64) + { + if (put_encoded_bits(s, te->code, te->length)) + return -1; + span -= te->run_length; + } + te = &tab[63 + (span >> 6)]; + if (span >= 64) + { + if (put_encoded_bits(s, te->code, te->length)) + return -1; + span -= te->run_length; + } + if (put_encoded_bits(s, tab[span].code, tab[span].length)) + return -1; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#define pixel_is_black(x,bit) (((x)[(bit) >> 3] << ((bit) & 7)) & 0x80) + +/* + * Write an EOL code to the output stream. We also handle writing the tag + * bit for the next scanline when doing 2D encoding. + */ +static void encode_eol(t4_state_t *s) +{ + uint32_t code; + int length; + + if (s->line_encoding == T4_COMPRESSION_ITU_T4_2D) + { + code = 0x0800 | ((!s->row_is_2d) << 12); + length = 13; + } + else + { + /* T.4 1D EOL, or T.6 EOFB */ + code = 0x800; + length = 12; + } + if (s->row_bits) + { + /* We may need to pad the row to a minimum length, unless we are in T.6 mode. + In T.6 we only come here at the end of the page to add the EOFB marker, which + is like two 1D EOLs. */ + if (s->line_encoding != T4_COMPRESSION_ITU_T6) + { + if (s->row_bits + length < s->t4_t6_tx.min_bits_per_row) + put_encoded_bits(s, 0, s->t4_t6_tx.min_bits_per_row - (s->row_bits + length)); + } + put_encoded_bits(s, code, length); + update_row_bit_info(s); + } + else + { + /* We don't pad zero length rows. They are the consecutive EOLs which end a page. */ + put_encoded_bits(s, code, length); + /* Don't do the full update row bit info, or the minimum suddenly drops to the + length of an EOL. Just clear the row bits, so we treat the next EOL as an + end of page EOL, with no padding. */ + s->row_bits = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +/* + * 2D-encode a row of pixels. Consult ITU specification T.4 for the algorithm. + */ +static void encode_2d_row(t4_state_t *s) +{ + static const t4_run_table_entry_t codes[] = + { + { 7, 0x60, 0 }, /* VR3 0000 011 */ + { 6, 0x30, 0 }, /* VR2 0000 11 */ + { 3, 0x06, 0 }, /* VR1 011 */ + { 1, 0x01, 0 }, /* V0 1 */ + { 3, 0x02, 0 }, /* VL1 010 */ + { 6, 0x10, 0 }, /* VL2 0000 10 */ + { 7, 0x20, 0 }, /* VL3 0000 010 */ + { 3, 0x04, 0 }, /* horizontal 001 */ + { 4, 0x08, 0 } /* pass 0001 */ + }; + + /* The reference or starting changing element on the coding line. At the start of the coding + line, a0 is set on an imaginary white changing element situated just before the first element + on the line. During the coding of the coding line, the position of a0 is defined by the + previous coding mode. (See T.4/4.2.1.3.2.) */ + int a0; + /* The next changing element to the right of a0 on the coding line. */ + int a1; + /* The next changing element to the right of a1 on the coding line. */ + int a2; + /* The first changing element on the reference line to the right of a0 and of opposite colour to a0. */ + int b1; + /* The next changing element to the right of b1 on the reference line. */ + int b2; + int diff; + int a_cursor; + int b_cursor; + int cur_steps; + uint32_t *p; + + /* + b1 b2 + XX XX XX XX XX -- -- -- -- -- XX XX XX -- -- -- -- -- + XX XX XX -- -- -- -- -- XX XX XX XX XX XX -- -- -- -- + a0 a1 a2 + + + a) Pass mode + This mode is identified when the position of b2 lies to the left of a1. When this mode + has been coded, a0 is set on the element of the coding line below b2 in preparation for + the next coding (i.e. on a0'). + + b1 b2 + XX XX XX XX -- -- XX XX XX -- -- -- -- -- + XX XX -- -- -- -- -- -- -- -- -- -- XX XX + a0 a0' a1 + Pass mode + + + However, the state where b2 occurs just above a1, as shown in the figure below, is not + considered as a pass mode. + + b1 b2 + XX XX XX XX -- -- XX XX XX -- -- -- -- -- + XX XX -- -- -- -- -- -- -- XX XX XX XX XX + a0 a1 + Not pass mode + + + b) Vertical mode + When this mode is identified, the position of a1 is coded relative to the position of b1. + The relative distance a1b1 can take on one of seven values V(0), VR(1), VR(2), VR(3), + VL(1), VL(2) and VL(3), each of which is represented by a separate code word. The + subscripts R and L indicate that a1 is to the right or left respectively of b1, and the + number in brackets indicates the value of the distance a1b1. After vertical mode coding + has occurred, the position of a0 is set on a1 (see figure below). + + c) Horizontal mode + When this mode is identified, both the run-lengths a0a1 and a1a2 are coded using the code + words H + M(a0a1) + M(a1a2). H is the flag code word 001 taken from the two-dimensional + code table. M(a0a1) and M(a1a2) are code words which represent the length and "colour" + of the runs a0a1 and a1a2 respectively and are taken from the appropriate white or black + one-dimensional code tables. After a horizontal mode coding, the position of a0 is set on + a2 (see figure below). + + Vertical + + b1 b2 + -- XX XX XX XX XX -- -- -- -- -- -- -- -- XX XX XX XX -- -- -- + -- -- -- -- -- -- -- -- -- -- -- -- XX XX XX XX XX XX XX -- -- + a0 a1 a2 + <-------- a0a1 --------><-------- a1a2 ------------> + Horizontal mode + Vertical and horizontal modes + */ + /* The following implements the 2-D encoding section of the flow chart in Figure7/T.4 */ + cur_steps = row_to_run_lengths(s->cur_runs, s->row_buf, s->image_width); + /* Stretch the row a little, so when we step by 2 we are guaranteed to + hit an entry showing the row length */ + s->cur_runs[cur_steps] = + s->cur_runs[cur_steps + 1] = + s->cur_runs[cur_steps + 2] = s->cur_runs[cur_steps - 1]; + + a0 = 0; + a1 = s->cur_runs[0]; + b1 = s->ref_runs[0]; + a_cursor = 0; + b_cursor = 0; + for (;;) + { + b2 = s->ref_runs[b_cursor + 1]; + if (b2 >= a1) + { + diff = b1 - a1; + if (abs(diff) <= 3) + { + /* Vertical mode coding */ + put_encoded_bits(s, codes[diff + 3].code, codes[diff + 3].length); + a0 = a1; + a_cursor++; + } + else + { + /* Horizontal mode coding */ + a2 = s->cur_runs[a_cursor + 1]; + put_encoded_bits(s, codes[7].code, codes[7].length); + if (a0 + a1 == 0 || pixel_is_black(s->row_buf, a0) == 0) + { + put_1d_span(s, a1 - a0, t4_white_codes); + put_1d_span(s, a2 - a1, t4_black_codes); + } + else + { + put_1d_span(s, a1 - a0, t4_black_codes); + put_1d_span(s, a2 - a1, t4_white_codes); + } + a0 = a2; + a_cursor += 2; + } + if (a0 >= s->image_width) + break; + if (a_cursor >= cur_steps) + a_cursor = cur_steps - 1; + a1 = s->cur_runs[a_cursor]; + } + else + { + /* Pass mode coding */ + put_encoded_bits(s, codes[8].code, codes[8].length); + /* We now set a0 to somewhere in the middle of its current run, + but we know are aren't moving beyond that run. */ + a0 = b2; + if (a0 >= s->image_width) + break; + } + /* We need to hunt for the correct position in the reference row, as the + runs there have no particular alignment with the runs in the current + row. */ + if (pixel_is_black(s->row_buf, a0)) + b_cursor |= 1; + else + b_cursor &= ~1; + if (a0 < (int) s->ref_runs[b_cursor]) + { + for ( ; b_cursor >= 0; b_cursor -= 2) + { + if (a0 >= (int) s->ref_runs[b_cursor]) + break; + } + b_cursor += 2; + } + else + { + for ( ; b_cursor < s->t4_t6_tx.ref_steps; b_cursor += 2) + { + if (a0 < (int) s->ref_runs[b_cursor]) + break; + } + if (b_cursor >= s->t4_t6_tx.ref_steps) + b_cursor = s->t4_t6_tx.ref_steps - 1; + } + b1 = s->ref_runs[b_cursor]; + } + /* Swap the buffers */ + s->t4_t6_tx.ref_steps = cur_steps; + p = s->cur_runs; + s->cur_runs = s->ref_runs; + s->ref_runs = p; +} +/*- End of function --------------------------------------------------------*/ + +/* + * 1D-encode a row of pixels. The encoding is a sequence of all-white or + * all-black spans of pixels encoded with Huffman codes. + */ +static void encode_1d_row(t4_state_t *s) +{ + int i; + + /* Do our work in the reference row buffer, and it is already in place if + we need a reference row for a following 2D encoded row. */ + s->t4_t6_tx.ref_steps = row_to_run_lengths(s->ref_runs, s->row_buf, s->image_width); + put_1d_span(s, s->ref_runs[0], t4_white_codes); + for (i = 1; i < s->t4_t6_tx.ref_steps; i++) + put_1d_span(s, s->ref_runs[i] - s->ref_runs[i - 1], (i & 1) ? t4_black_codes : t4_white_codes); + /* Stretch the row a little, so when we step by 2 we are guaranteed to + hit an entry showing the row length */ + s->ref_runs[s->t4_t6_tx.ref_steps] = + s->ref_runs[s->t4_t6_tx.ref_steps + 1] = + s->ref_runs[s->t4_t6_tx.ref_steps + 2] = s->ref_runs[s->t4_t6_tx.ref_steps - 1]; +} +/*- End of function --------------------------------------------------------*/ + +static int encode_row(t4_state_t *s) +{ + switch (s->line_encoding) + { + case T4_COMPRESSION_ITU_T6: + /* T.6 compression is a trivial step up from T.4 2D, so we just + throw it in here. T.6 is only used with error correction, + so it does not need independantly compressed (i.e. 1D) lines + to recover from data errors. It doesn't need EOLs, either. */ + if (s->row_bits) + update_row_bit_info(s); + encode_2d_row(s); + break; + case T4_COMPRESSION_ITU_T4_2D: + encode_eol(s); + if (s->row_is_2d) + { + encode_2d_row(s); + s->t4_t6_tx.rows_to_next_1d_row--; + } + else + { + encode_1d_row(s); + s->row_is_2d = TRUE; + } + if (s->t4_t6_tx.rows_to_next_1d_row <= 0) + { + /* Insert a row of 1D encoding */ + s->row_is_2d = FALSE; + s->t4_t6_tx.rows_to_next_1d_row = s->t4_t6_tx.max_rows_to_next_1d_row - 1; + } + break; + default: + case T4_COMPRESSION_ITU_T4_1D: + encode_eol(s); + encode_1d_row(s); + break; + } + s->row++; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_state_t *s, t4_row_read_handler_t handler, void *user_data) +{ + s->t4_t6_tx.row_read_handler = handler; + s->t4_t6_tx.row_read_user_data = user_data; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(t4_state_t *) t4_tx_init(t4_state_t *s, const char *file, int start_page, int stop_page) +{ + int run_space; + + if (s == NULL) + { + if ((s = (t4_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + span_log_init(&s->logging, SPAN_LOG_NONE, NULL); + span_log_set_protocol(&s->logging, "T.4"); + s->rx = FALSE; + + span_log(&s->logging, SPAN_LOG_FLOW, "Start tx document\n"); + + if (open_tiff_input_file(s, file) < 0) + return NULL; + s->tiff.file = strdup(file); + s->current_page = + s->tiff.start_page = (start_page >= 0) ? start_page : 0; + s->tiff.stop_page = (stop_page >= 0) ? stop_page : INT_MAX; + + if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page)) + return NULL; + if (get_tiff_directory_info(s)) + { + close_tiff_input_file(s); + return NULL; + } + + s->t4_t6_tx.rows_to_next_1d_row = s->t4_t6_tx.max_rows_to_next_1d_row - 1; + + s->tiff.pages_in_file = -1; + + run_space = (s->image_width + 4)*sizeof(uint32_t); + if ((s->cur_runs = (uint32_t *) malloc(run_space)) == NULL) + return NULL; + if ((s->ref_runs = (uint32_t *) malloc(run_space)) == NULL) + { + free_buffers(s); + close_tiff_input_file(s); + return NULL; + } + if ((s->row_buf = malloc(s->bytes_per_row)) == NULL) + { + free_buffers(s); + close_tiff_input_file(s); + return NULL; + } + s->ref_runs[0] = + s->ref_runs[1] = + s->ref_runs[2] = + s->ref_runs[3] = s->image_width; + s->t4_t6_tx.ref_steps = 1; + s->image_buffer_size = 0; + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_start_page(t4_state_t *s) +{ + int row; + int i; + int run_space; + int len; + int old_image_width; + uint8_t *bufptr8; + uint32_t *bufptr; + + span_log(&s->logging, SPAN_LOG_FLOW, "Start tx page %d\n", s->current_page); + if (s->current_page > s->tiff.stop_page) + return -1; + if (s->tiff.tiff_file == NULL) + return -1; + old_image_width = s->image_width; + if (s->t4_t6_tx.row_read_handler == NULL) + { +#if defined(HAVE_LIBTIFF) + if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page)) + return -1; + get_tiff_directory_info(s); +#endif + } + s->image_size = 0; + s->tx_bitstream = 0; + s->tx_bits = 0; + s->row_is_2d = (s->line_encoding == T4_COMPRESSION_ITU_T6); + s->t4_t6_tx.rows_to_next_1d_row = s->t4_t6_tx.max_rows_to_next_1d_row - 1; + + /* Allow for pages being of different width. */ + run_space = (s->image_width + 4)*sizeof(uint32_t); + if (old_image_width != s->image_width) + { + s->bytes_per_row = (s->image_width + 7)/8; + + if ((bufptr = (uint32_t *) realloc(s->cur_runs, run_space)) == NULL) + return -1; + s->cur_runs = bufptr; + if ((bufptr = (uint32_t *) realloc(s->ref_runs, run_space)) == NULL) + return -1; + s->ref_runs = bufptr; + if ((bufptr8 = realloc(s->row_buf, s->bytes_per_row)) == NULL) + return -1; + s->row_buf = bufptr8; + } + s->ref_runs[0] = + s->ref_runs[1] = + s->ref_runs[2] = + s->ref_runs[3] = s->image_width; + s->t4_t6_tx.ref_steps = 1; + + s->row_bits = 0; + s->min_row_bits = INT_MAX; + s->max_row_bits = 0; + + if (s->t4_t6_tx.header_info && s->t4_t6_tx.header_info[0]) + { + if (t4_tx_put_fax_header(s)) + return -1; + } + if (s->t4_t6_tx.row_read_handler) + { + for (row = 0; ; row++) + { + if ((len = s->t4_t6_tx.row_read_handler(s->t4_t6_tx.row_read_user_data, s->row_buf, s->bytes_per_row)) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error at row %d.\n", s->tiff.file, row); + break; + } + if (len == 0) + break; + if (encode_row(s)) + return -1; + } + s->image_length = row; + } + else + { + if ((s->image_length = read_tiff_image(s)) < 0) + return -1; + } + if (s->line_encoding == T4_COMPRESSION_ITU_T6) + { + /* Attach an EOFB (end of facsimile block == 2 x EOLs) to the end of the page */ + for (i = 0; i < EOLS_TO_END_T6_TX_PAGE; i++) + encode_eol(s); + } + else + { + /* Attach an RTC (return to control == 6 x EOLs) to the end of the page */ + s->row_is_2d = FALSE; + for (i = 0; i < EOLS_TO_END_T4_TX_PAGE; i++) + encode_eol(s); + } + + /* Force any partial byte in progress to flush using ones. Any post EOL padding when + sending is normally ones, so this is consistent. */ + put_encoded_bits(s, 0xFF, 7); + s->t4_t6_tx.bit_pos = 7; + s->t4_t6_tx.bit_ptr = 0; + s->line_image_size = s->image_size*8; + + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_state_t *s) +{ + span_log(&s->logging, SPAN_LOG_FLOW, "Checking for the existance of page %d\n", s->current_page + 1); + if (s->current_page >= s->tiff.stop_page) + return -1; + if (s->t4_t6_tx.row_read_handler == NULL) + { +#if defined(HAVE_LIBTIFF) + if (s->tiff.tiff_file == NULL) + return -1; + if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page + 1)) + return -1; + return test_tiff_directory_info(s); +#endif + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_restart_page(t4_state_t *s) +{ + s->t4_t6_tx.bit_pos = 7; + s->t4_t6_tx.bit_ptr = 0; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_end_page(t4_state_t *s) +{ + s->current_page++; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_bit(t4_state_t *s) +{ + int bit; + + if (s->t4_t6_tx.bit_ptr >= s->image_size) + return SIG_STATUS_END_OF_DATA; + bit = (s->image_buffer[s->t4_t6_tx.bit_ptr] >> (7 - s->t4_t6_tx.bit_pos)) & 1; + if (--s->t4_t6_tx.bit_pos < 0) + { + s->t4_t6_tx.bit_pos = 7; + s->t4_t6_tx.bit_ptr++; + } + return bit; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_byte(t4_state_t *s) +{ + if (s->t4_t6_tx.bit_ptr >= s->image_size) + return 0x100; + return s->image_buffer[s->t4_t6_tx.bit_ptr++]; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_chunk(t4_state_t *s, uint8_t buf[], int max_len) +{ + if (s->t4_t6_tx.bit_ptr >= s->image_size) + return 0; + if (s->t4_t6_tx.bit_ptr + max_len > s->image_size) + max_len = s->image_size - s->t4_t6_tx.bit_ptr; + memcpy(buf, &s->image_buffer[s->t4_t6_tx.bit_ptr], max_len); + s->t4_t6_tx.bit_ptr += max_len; + return max_len; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_check_bit(t4_state_t *s) +{ + int bit; + + if (s->t4_t6_tx.bit_ptr >= s->image_size) + return SIG_STATUS_END_OF_DATA; + bit = (s->image_buffer[s->t4_t6_tx.bit_ptr] >> s->t4_t6_tx.bit_pos) & 1; + return bit; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_release(t4_state_t *s) +{ + if (s->rx) + return -1; + if (s->tiff.tiff_file) + close_tiff_input_file(s); + free_buffers(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_free(t4_state_t *s) +{ + int ret; + + ret = t4_tx_release(s); + free(s); + return ret; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_tx_set_tx_encoding(t4_state_t *s, int encoding) +{ + s->line_encoding = encoding; + s->t4_t6_tx.rows_to_next_1d_row = s->t4_t6_tx.max_rows_to_next_1d_row - 1; + s->row_is_2d = FALSE; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_tx_set_min_row_bits(t4_state_t *s, int bits) +{ + s->t4_t6_tx.min_bits_per_row = bits; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_tx_set_local_ident(t4_state_t *s, const char *ident) +{ + s->tiff.local_ident = (ident && ident[0]) ? ident : NULL; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t4_tx_set_header_info(t4_state_t *s, const char *info) +{ + s->t4_t6_tx.header_info = (info && info[0]) ? info : NULL; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_y_resolution(t4_state_t *s) +{ + return s->y_resolution; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_state_t *s) +{ + return s->x_resolution; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_image_width(t4_state_t *s) +{ + return s->image_width; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_state_t *s) +{ + int max; + + max = 0; + if (s->t4_t6_tx.row_read_handler == NULL) + max = get_tiff_total_pages(s); + if (max >= 0) + s->tiff.pages_in_file = max; + return max; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_current_page_in_file(t4_state_t *s) +{ + return s->current_page; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v17rx.c b/libs/spandsp/src/v17rx.c index 322bd155bb..bb3803de40 100644 --- a/libs/spandsp/src/v17rx.c +++ b/libs/spandsp/src/v17rx.c @@ -23,7 +23,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v17rx.c,v 1.153 2009/07/09 14:17:57 steveu Exp $ + * $Id: v17rx.c,v 1.153.4.4 2009/12/19 14:18:13 steveu Exp $ */ /*! \file */ @@ -121,22 +121,28 @@ enum /* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */ /* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */ /* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */ +#define SIN_LOW_BAND_EDGE 0.453990499f +#define COS_LOW_BAND_EDGE 0.891006542f +#define SIN_HIGH_BAND_EDGE 0.707106781f +#define COS_HIGH_BAND_EDGE -0.707106781f +#define ALPHA 0.99f + #if defined(SPANDSP_USE_FIXED_POINTx) -#define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR* 1.764193f)) /* 2*alpha*cos(low_edge) */ -#define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */ -#define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*-1.400072f)) /* 2*alpha*cos(high_edge) */ -#define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */ -#define SYNC_CROSS_CORR_COEFF_A ((int)(FP_FACTOR*-0.932131f)) /* -alpha^2*sin(freq_diff) */ -#define SYNC_CROSS_CORR_COEFF_B ((int)(FP_FACTOR* 0.700036f)) /* alpha*sin(high_edge) */ -#define SYNC_CROSS_CORR_COEFF_C ((int)(FP_FACTOR*-0.449451f)) /* -alpha*sin(low_edge) */ +#define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_LOW_BAND_EDGE))) +#define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA))) +#define SYNC_LOW_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_LOW_BAND_EDGE))) +#define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_HIGH_BAND_EDGE))) +#define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA))) +#define SYNC_HIGH_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_HIGH_BAND_EDGE))) +#define SYNC_MIXED_EDGES_COEFF_3 ((int)(FP_FACTOR*(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE)))) #else -#define SYNC_LOW_BAND_EDGE_COEFF_0 1.764193f /* 2*alpha*cos(low_edge) */ -#define SYNC_LOW_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */ -#define SYNC_HIGH_BAND_EDGE_COEFF_0 -1.400072f /* 2*alpha*cos(high_edge) */ -#define SYNC_HIGH_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */ -#define SYNC_CROSS_CORR_COEFF_A -0.932131f /* -alpha^2*sin(freq_diff) */ -#define SYNC_CROSS_CORR_COEFF_B 0.700036f /* alpha*sin(high_edge) */ -#define SYNC_CROSS_CORR_COEFF_C -0.449451f /* -alpha*sin(low_edge) */ +#define SYNC_LOW_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_LOW_BAND_EDGE) +#define SYNC_LOW_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA) +#define SYNC_LOW_BAND_EDGE_COEFF_2 (-ALPHA*SIN_LOW_BAND_EDGE) +#define SYNC_HIGH_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_HIGH_BAND_EDGE) +#define SYNC_HIGH_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA) +#define SYNC_HIGH_BAND_EDGE_COEFF_2 (-ALPHA*SIN_HIGH_BAND_EDGE) +#define SYNC_MIXED_EDGES_COEFF_3 (-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE)) #endif #if defined(SPANDSP_USE_FIXED_POINTx) @@ -533,12 +539,18 @@ static __inline__ void symbol_sync(v17_rx_state_t *s) /* This routine adapts the position of the half baud samples entering the equalizer. */ + /* This symbol sync scheme is based on the technique first described by Dominique Godard in + Passband Timing Recovery in an All-Digital Modem Receiver + IEEE TRANSACTIONS ON COMMUNICATIONS, VOL. COM-26, NO. 5, MAY 1978 */ + + /* This is slightly rearranged for figure 3b of the Godard paper, as this saves a couple of + maths operations */ #if defined(SPANDSP_USE_FIXED_POINTx) /* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */ /* Cross correlate */ - v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_A - + (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_B - + (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_C; + v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_LOW_BAND_EDGE_COEFF_2 + - (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_HIGH_BAND_EDGE_COEFF_2 + + (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_MIXED_EDGES_COEFF_3; /* Filter away any DC component */ p = v - s->symbol_sync_dc_filter[1]; s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0]; @@ -548,9 +560,9 @@ static __inline__ void symbol_sync(v17_rx_state_t *s) if (abs(s->baud_phase) > 100*FP_FACTOR) { if (s->baud_phase > 0) - i = (s->baud_phase > 1000*FP_FACTOR) ? 5 : 1; + i = (s->baud_phase > 1000*FP_FACTOR) ? 15 : 1; else - i = (s->baud_phase < -1000*FP_FACTOR) ? -5 : -1; + i = (s->baud_phase < -1000*FP_FACTOR) ? -15 : -1; //printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction); s->eq_put_step += i; @@ -558,9 +570,9 @@ static __inline__ void symbol_sync(v17_rx_state_t *s) } #else /* Cross correlate */ - v = s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_A - + s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_B - + s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_CROSS_CORR_COEFF_C; + v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2 + - s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_2 + + s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_MIXED_EDGES_COEFF_3; /* Filter away any DC component */ p = v - s->symbol_sync_dc_filter[1]; diff --git a/libs/spandsp/src/v18.c b/libs/spandsp/src/v18.c index 50df3c156e..067bd9e251 100644 --- a/libs/spandsp/src/v18.c +++ b/libs/spandsp/src/v18.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v18.c,v 1.10 2009/06/02 16:03:56 steveu Exp $ + * $Id: v18.c,v 1.12 2009/11/04 15:52:06 steveu Exp $ */ /*! \file */ @@ -738,7 +738,7 @@ SPAN_DECLARE(logging_state_t *) v18_get_logging_state(v18_state_t *s) /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, - int caller, + int calling_party, int mode, put_msg_func_t put_msg, void *user_data) @@ -749,7 +749,7 @@ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, return NULL; } memset(s, 0, sizeof(*s)); - s->caller = caller; + s->calling_party = calling_party; s->mode = mode; s->put_msg = put_msg; s->user_data = user_data; @@ -763,7 +763,7 @@ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, s->baudot_tx_shift = 2; /* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and ride over the fraction. */ - fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], 7, v18_tdd_put_async_byte, s); + fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s); s->baudot_rx_shift = 0; break; case V18_MODE_5BIT_50: @@ -773,7 +773,7 @@ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, s->baudot_tx_shift = 2; /* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and ride over the fraction. */ - fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT50], 7, v18_tdd_put_async_byte, s); + fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT50], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s); s->baudot_rx_shift = 0; break; case V18_MODE_DTMF: diff --git a/libs/spandsp/src/v22bis_rx.c b/libs/spandsp/src/v22bis_rx.c index 23a446b7d4..fc5e3a9f23 100644 --- a/libs/spandsp/src/v22bis_rx.c +++ b/libs/spandsp/src/v22bis_rx.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v22bis_rx.c,v 1.68 2009/06/02 16:03:56 steveu Exp $ + * $Id: v22bis_rx.c,v 1.69 2009/11/04 15:52:06 steveu Exp $ */ /*! \file */ @@ -490,7 +490,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample) error could be higher. */ s->rx.gardner_step = 4; s->rx.pattern_repeats = 0; - if (s->caller) + if (s->calling_party) s->rx.training = V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES; else s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200; @@ -586,7 +586,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample) span_log(&s->logging, SPAN_LOG_FLOW, "+++ S1 detected (%d long)\n", s->rx.pattern_repeats); if (s->bit_rate == 2400) { - if (!s->caller) + if (!s->calling_party) { /* Accept establishment at 2400bps */ span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting U0011 (S1) (Answerer)\n"); @@ -601,7 +601,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample) if (s->rx.training_count >= ms_to_symbols(270)) { /* If we haven't seen the S1 signal by now, we are committed to be in 1200bps mode */ - if (s->caller) + if (s->calling_party) { span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx normal operation (1200)\n"); /* The transmit side needs to sustain the scrambled ones for a timed period */ @@ -625,7 +625,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample) } else { - if (s->caller) + if (s->calling_party) { if (s->rx.training_count >= ms_to_symbols(100 + 450)) { @@ -716,7 +716,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l /* Calculate the I filter, with an arbitrary phase step, just so we can calculate the signal power of the required carrier, with any guard tone or spillback of our own transmitted signal suppressed. */ - if (s->caller) + if (s->calling_party) { ii = rx_pulseshaper_2400_re[6][0]*s->rx.rrc_filter[s->rx.rrc_filter_step]; for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++) @@ -769,7 +769,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l if (step > PULSESHAPER_COEFF_SETS - 1) step = PULSESHAPER_COEFF_SETS - 1; s->rx.eq_put_step += PULSESHAPER_COEFF_SETS*40/(3*2); - if (s->caller) + if (s->calling_party) { ii = rx_pulseshaper_2400_re[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step]; qq = rx_pulseshaper_2400_im[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step]; @@ -836,7 +836,7 @@ int v22bis_rx_restart(v22bis_state_t *s) s->rx.training_count = 0; s->rx.signal_present = FALSE; - s->rx.carrier_phase_rate = dds_phase_ratef((s->caller) ? 2400.0f : 1200.0f); + s->rx.carrier_phase_rate = dds_phase_ratef((s->calling_party) ? 2400.0f : 1200.0f); s->rx.carrier_phase = 0; power_meter_init(&(s->rx.rx_power), 5); v22bis_rx_signal_cutoff(s, -45.5f); @@ -855,7 +855,7 @@ int v22bis_rx_restart(v22bis_state_t *s) s->rx.training_error = 0.0f; s->rx.total_baud_timing_correction = 0; /* We want the carrier to pull in faster on the answerer side, as it has very little time to adapt. */ - s->rx.carrier_track_i = (s->caller) ? 8000.0f : 40000.0f; + s->rx.carrier_track_i = (s->calling_party) ? 8000.0f : 40000.0f; s->rx.carrier_track_p = 8000000.0f; s->negotiated_bit_rate = 1200; diff --git a/libs/spandsp/src/v22bis_tx.c b/libs/spandsp/src/v22bis_tx.c index 30fcf59ec5..58a0bd589b 100644 --- a/libs/spandsp/src/v22bis_tx.c +++ b/libs/spandsp/src/v22bis_tx.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v22bis_tx.c,v 1.63 2009/06/02 16:03:56 steveu Exp $ + * $Id: v22bis_tx.c,v 1.64 2009/11/04 15:52:06 steveu Exp $ */ /*! \file */ @@ -346,7 +346,7 @@ static complexf_t training_get(v22bis_state_t *s) if (++s->tx.training_count >= ms_to_symbols(100)) { span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 after U0011\n"); - if (s->caller) + if (s->calling_party) { s->tx.training_count = 0; s->tx.training = V22BIS_TX_TRAINING_STAGE_S11; @@ -523,7 +523,7 @@ static int v22bis_tx_restart(v22bis_state_t *s) s->tx.rrc_filter_step = 0; s->tx.scramble_reg = 0; s->tx.scrambler_pattern_count = 0; - if (s->caller) + if (s->calling_party) s->tx.training = V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE; else s->tx.training = V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE; @@ -634,7 +634,7 @@ SPAN_DECLARE(int) v22bis_current_bit_rate(v22bis_state_t *s) SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s, int bit_rate, int guard, - int caller, + int calling_party, get_bit_func_t get_bit, void *get_bit_user_data, put_bit_func_t put_bit, @@ -657,14 +657,14 @@ SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s, span_log_init(&s->logging, SPAN_LOG_NONE, NULL); span_log_set_protocol(&s->logging, "V.22bis"); s->bit_rate = bit_rate; - s->caller = caller; + s->calling_party = calling_party; s->get_bit = get_bit; s->get_bit_user_data = get_bit_user_data; s->put_bit = put_bit; s->put_bit_user_data = put_bit_user_data; - if (s->caller) + if (s->calling_party) { s->tx.carrier_phase_rate = dds_phase_ratef(1200.0f); } diff --git a/libs/spandsp/src/v29rx.c b/libs/spandsp/src/v29rx.c index 47fa1b24f1..ee120b64a9 100644 --- a/libs/spandsp/src/v29rx.c +++ b/libs/spandsp/src/v29rx.c @@ -23,7 +23,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v29rx.c,v 1.167 2009/07/08 15:11:09 steveu Exp $ + * $Id: v29rx.c,v 1.167.4.4 2009/12/19 14:18:13 steveu Exp $ */ /*! \file */ @@ -131,22 +131,28 @@ static const uint8_t space_map_9600[20][20] = /* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */ /* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */ /* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */ +#define SIN_LOW_BAND_EDGE 0.382683432f +#define COS_LOW_BAND_EDGE 0.923879533f +#define SIN_HIGH_BAND_EDGE 0.760405966f +#define COS_HIGH_BAND_EDGE -0.649448048f +#define ALPHA 0.99f + #if defined(SPANDSP_USE_FIXED_POINT) -#define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR* 1.829281f)) /* 2*alpha*cos(low_edge) */ -#define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */ -#define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*-1.285907f)) /* 2*alpha*cos(high_edge) */ -#define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */ -#define SYNC_CROSS_CORR_COEFF_A ((int)(FP_FACTOR*-0.932131f)) /* -alpha^2*sin(freq_diff) */ -#define SYNC_CROSS_CORR_COEFF_B ((int)(FP_FACTOR* 0.752802f)) /* alpha*sin(high_edge) */ -#define SYNC_CROSS_CORR_COEFF_C ((int)(FP_FACTOR*-0.378857f)) /* -alpha*sin(low_edge) */ +#define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_LOW_BAND_EDGE))) +#define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA))) +#define SYNC_LOW_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_LOW_BAND_EDGE))) +#define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_HIGH_BAND_EDGE))) +#define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA))) +#define SYNC_HIGH_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_HIGH_BAND_EDGE))) +#define SYNC_MIXED_EDGES_COEFF_3 ((int)(FP_FACTOR*(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE)))) #else -#define SYNC_LOW_BAND_EDGE_COEFF_0 1.829281f /* 2*alpha*cos(low_edge) */ -#define SYNC_LOW_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */ -#define SYNC_HIGH_BAND_EDGE_COEFF_0 -1.285907f /* 2*alpha*cos(high_edge) */ -#define SYNC_HIGH_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */ -#define SYNC_CROSS_CORR_COEFF_A -0.932131f /* -alpha^2*sin(freq_diff) */ -#define SYNC_CROSS_CORR_COEFF_B 0.752802f /* alpha*sin(high_edge) */ -#define SYNC_CROSS_CORR_COEFF_C -0.378857f /* -alpha*sin(low_edge) */ +#define SYNC_LOW_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_LOW_BAND_EDGE) +#define SYNC_LOW_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA) +#define SYNC_LOW_BAND_EDGE_COEFF_2 (-ALPHA*SIN_LOW_BAND_EDGE) +#define SYNC_HIGH_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_HIGH_BAND_EDGE) +#define SYNC_HIGH_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA) +#define SYNC_HIGH_BAND_EDGE_COEFF_2 (-ALPHA*SIN_HIGH_BAND_EDGE) +#define SYNC_MIXED_EDGES_COEFF_3 (-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE)) #endif SPAN_DECLARE(float) v29_rx_carrier_frequency(v29_rx_state_t *s) @@ -489,12 +495,18 @@ static __inline__ void symbol_sync(v29_rx_state_t *s) /* This routine adapts the position of the half baud samples entering the equalizer. */ + /* This symbol sync scheme is based on the technique first described by Dominique Godard in + Passband Timing Recovery in an All-Digital Modem Receiver + IEEE TRANSACTIONS ON COMMUNICATIONS, VOL. COM-26, NO. 5, MAY 1978 */ + + /* This is slightly rearranged for figure 3b of the Godard paper, as this saves a couple of + maths operations */ #if defined(SPANDSP_USE_FIXED_POINT) /* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */ /* Cross correlate */ - v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_A - + (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_B - + (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_C; + v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_LOW_BAND_EDGE_COEFF_2 + - (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_HIGH_BAND_EDGE_COEFF_2 + + (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_MIXED_EDGES_COEFF_3; /* Filter away any DC component */ p = v - s->symbol_sync_dc_filter[1]; s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0]; @@ -514,9 +526,9 @@ static __inline__ void symbol_sync(v29_rx_state_t *s) } #else /* Cross correlate */ - v = s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_A - + s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_B - + s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_CROSS_CORR_COEFF_C; + v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2 + - s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_2 + + s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_MIXED_EDGES_COEFF_3; /* Filter away any DC component */ p = v - s->symbol_sync_dc_filter[1]; s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0]; diff --git a/libs/spandsp/src/v42.c b/libs/spandsp/src/v42.c index 718985b7c2..1c6ed0803d 100644 --- a/libs/spandsp/src/v42.c +++ b/libs/spandsp/src/v42.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v42.c,v 1.50 2009/02/10 13:06:47 steveu Exp $ + * $Id: v42.c,v 1.51 2009/11/04 15:52:06 steveu Exp $ */ /* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. */ @@ -1138,11 +1138,11 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit) break; /*endif*/ s->rxstream &= 0x3FF; - if (s->caller && s->rxstream == 0x145) + if (s->calling_party && s->rxstream == 0x145) { s->rx_negotiation_step++; } - else if (!s->caller && s->rxstream == 0x111) + else if (!s->calling_party && s->rxstream == 0x111) { s->rx_negotiation_step++; } @@ -1174,15 +1174,15 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit) break; /*endif*/ s->rxstream &= 0x3FF; - if (s->caller && s->rxstream == 0x185) + if (s->calling_party && s->rxstream == 0x185) { s->rx_negotiation_step++; } - else if (s->caller && s->rxstream == 0x001) + else if (s->calling_party && s->rxstream == 0x001) { s->rx_negotiation_step++; } - else if (!s->caller && s->rxstream == 0x113) + else if (!s->calling_party && s->rxstream == 0x113) { s->rx_negotiation_step++; } @@ -1206,7 +1206,7 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit) { /* HIT */ s->rx_negotiation_step++; - if (s->caller) + if (s->calling_party) { if (s->t400_timer >= 0) { @@ -1252,7 +1252,7 @@ static int v42_support_negotiation_tx_bit(v42_state_t *s) { int bit; - if (s->caller) + if (s->calling_party) { if (s->txbits <= 0) { @@ -1355,7 +1355,7 @@ SPAN_DECLARE(void) v42_restart(v42_state_t *s) { span_schedule_init(&s->lapm.sched); - s->lapm.we_are_originator = s->caller; + s->lapm.we_are_originator = s->calling_party; lapm_restart(&s->lapm); if (s->detect) { @@ -1379,7 +1379,7 @@ fprintf(stderr, "Setting T400 i\n"); } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int caller, int detect, v42_frame_handler_t frame_handler, void *user_data) +SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int calling_party, int detect, v42_frame_handler_t frame_handler, void *user_data) { int alloced; @@ -1394,7 +1394,7 @@ SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int caller, int detect, v42 alloced = TRUE; } memset(s, 0, sizeof(*s)); - s->caller = caller; + s->calling_party = calling_party; s->detect = detect; s->lapm.iframe_receive = frame_handler; s->lapm.iframe_receive_user_data = user_data; diff --git a/libs/spandsp/src/v8.c b/libs/spandsp/src/v8.c index 69e9e92b3e..4cc9b597fe 100644 --- a/libs/spandsp/src/v8.c +++ b/libs/spandsp/src/v8.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v8.c,v 1.39 2009/06/24 00:34:38 steveu Exp $ + * $Id: v8.c,v 1.42 2009/11/04 16:10:14 steveu Exp $ */ /*! \file */ @@ -47,6 +47,7 @@ #include "spandsp/logging.h" #include "spandsp/queue.h" #include "spandsp/async.h" +#include "spandsp/vector_int.h" #include "spandsp/complex.h" #include "spandsp/dds.h" #include "spandsp/tone_detect.h" @@ -67,7 +68,6 @@ enum { V8_WAIT_1S, - V8_CI, V8_CI_ON, V8_CI_OFF, V8_HEARD_ANSAM, @@ -76,7 +76,6 @@ enum V8_CM_WAIT, V8_SIGC, - V8_WAIT_200MS, V8_JM_ON, V8_SIGA, @@ -91,6 +90,23 @@ enum V8_SYNC_V92 } v8_sync_types_e; +enum +{ + V8_CALL_FUNCTION_TAG = 0x01, + V8_MODULATION_TAG = 0x05, + V8_PROTOCOLS_TAG = 0x0A, + V8_PSTN_ACCESS_TAG = 0x0D, + V8_NSF_TAG = 0x0F, + V8_PCM_MODEM_AVAILABILITY_TAG = 0x07, + V8_T66_TAG = 0x0E +}; + +enum +{ + V8_CI_SYNC_OCTET = 0x00, + V8_CM_JM_SYNC_OCTET = 0xE0 +}; + SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function) { switch (call_function) @@ -172,12 +188,85 @@ SPAN_DECLARE(const char *) v8_protocol_to_str(int protocol) SPAN_DECLARE(const char *) v8_pstn_access_to_str(int pstn_access) { + switch (pstn_access) + { + case V8_PSTN_ACCESS_CALL_DCE_CELLULAR: + return "Calling modem on cellular"; + case V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR: + return "Answering modem on cellular"; + case V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR: + return "Answering and calling modems on cellular"; + case V8_PSTN_ACCESS_DCE_ON_DIGITAL: + return "DCE on digital"; + case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_CALL_DCE_CELLULAR: + return "DCE on digital, and calling modem on cellular"; + case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR: + return "DCE on digital, answering modem on cellular"; + case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR: + return "DCE on digital, and answering and calling modems on cellular"; + } + return "???"; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(const char *) v8_nsf_to_str(int nsf) +{ + switch (nsf) + { + case 0: + return "???"; + } return "???"; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(const char *) v8_pcm_modem_availability_to_str(int pcm_modem_availability) { + switch (pcm_modem_availability) + { + case 0: + return "PCM unavailable"; + case V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: + return "V.90/V.92 analogue available"; + case V8_PSTN_PCM_MODEM_V90_V92_DIGITAL: + return "V.90/V.92 digital available"; + case V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: + return "V.90/V.92 digital/analogue available"; + case V8_PSTN_PCM_MODEM_V91: + return "V.91 available"; + case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: + return "V.91 and V.90/V.92 analogue available"; + case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL: + return "V.91 and V.90/V.92 digital available"; + case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: + return "V.91 and V.90/V.92 digital/analogue available"; + } + return "???"; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(const char *) v8_t66_to_str(int t66) +{ + /* T.66 doesn't really define any V.8 values. The bits are all reserved. */ + switch (t66) + { + case 0: + return "???"; + case 1: + return "Reserved TIA"; + case 2: + return "Reserved"; + case 3: + return "Reserved TIA + others"; + case 4: + return "Reserved"; + case 5: + return "Reserved TIA + others"; + case 6: + return "Reserved"; + case 7: + return "Reserved TIA + others"; + } return "???"; } /*- End of function --------------------------------------------------------*/ @@ -203,11 +292,8 @@ SPAN_DECLARE(void) v8_log_supported_modulations(v8_state_t *s, int modulation_sc static const uint8_t *process_call_function(v8_state_t *s, const uint8_t *p) { - int call_function; - - call_function = (*p >> 5) & 0x07; - span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_call_function_to_str(call_function)); - s->call_function = call_function; + s->result.call_function = (*p >> 5) & 0x07; + span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_call_function_to_str(s->result.call_function)); return ++p; } /*- End of function --------------------------------------------------------*/ @@ -225,6 +311,7 @@ static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p) if (*p & 0x20) far_end_modulations |= V8_MOD_V90; + /* Check for an extension octet */ if ((*++p & 0x38) == 0x10) { if (*p & 0x80) @@ -238,6 +325,7 @@ static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p) if (*p & 0x01) far_end_modulations |= V8_MOD_V32; + /* Check for an extension octet */ if ((*++p & 0x38) == 0x10) { if (*p & 0x80) @@ -250,77 +338,59 @@ static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p) far_end_modulations |= V8_MOD_V26BIS; if (*p & 0x01) far_end_modulations |= V8_MOD_V26TER; - /* Skip any future extensions we do not understand */ - while ((*++p & 0x38) == 0x10) - /* dummy loop */; } } - s->far_end_modulations = far_end_modulations; - v8_log_supported_modulations(s, s->far_end_modulations); + s->result.far_end_modulations = far_end_modulations; + v8_log_supported_modulations(s, s->result.far_end_modulations); return ++p; } /*- End of function --------------------------------------------------------*/ static const uint8_t *process_protocols(v8_state_t *s, const uint8_t *p) { - int protocol; - - protocol = (*p >> 5) & 0x07; - span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_protocol_to_str(protocol)); - s->protocol = protocol; + s->result.protocol = (*p >> 5) & 0x07; + span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_protocol_to_str(s->result.protocol)); return ++p; } /*- End of function --------------------------------------------------------*/ static const uint8_t *process_pstn_access(v8_state_t *s, const uint8_t *p) { - int pstn_access; - - pstn_access = (*p >> 5) & 0x07; - if (pstn_access & V8_PSTN_ACCESS_DCE_ON_DIGTIAL) - span_log(&s->logging, SPAN_LOG_FLOW, "DCE on digital network connection\n"); - else - span_log(&s->logging, SPAN_LOG_FLOW, "DCE on analogue network connection\n"); - if (pstn_access & V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR) - span_log(&s->logging, SPAN_LOG_FLOW, "Answer DCE on cellular connection\n"); - if (pstn_access & V8_PSTN_ACCESS_CALL_DCE_CELLULAR) - span_log(&s->logging, SPAN_LOG_FLOW, "Call DCE on cellular connection\n"); + s->result.pstn_access = (*p >> 5) & 0x07; + span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_pstn_access_to_str(s->result.pstn_access)); return ++p; } /*- End of function --------------------------------------------------------*/ static const uint8_t *process_non_standard_facilities(v8_state_t *s, const uint8_t *p) { - ++p; - p += *p; + s->result.nsf = (*p >> 5) & 0x07; + s->result.nsf_seen = TRUE; + span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_nsf_to_str(s->result.nsf)); return p; } /*- End of function --------------------------------------------------------*/ static const uint8_t *process_pcm_modem_availability(v8_state_t *s, const uint8_t *p) { - int pcm_availability; - - pcm_availability = (*p >> 5) & 0x07; - if (pcm_availability & V8_PSTN_PCM_MODEM_V91) - span_log(&s->logging, SPAN_LOG_FLOW, "V.91 available\n"); - if (pcm_availability & V8_PSTN_PCM_MODEM_V90_V92_DIGITAL) - span_log(&s->logging, SPAN_LOG_FLOW, "V.90 or V.92 digital modem available\n"); - if (pcm_availability & V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE) - span_log(&s->logging, SPAN_LOG_FLOW, "V.90 or V.92 analogue modem available\n"); + s->result.pcm_modem_availability = (*p >> 5) & 0x07; + span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_pcm_modem_availability_to_str(s->result.pcm_modem_availability)); return ++p; } /*- End of function --------------------------------------------------------*/ static const uint8_t *process_t66(v8_state_t *s, const uint8_t *p) { + s->result.t66 = (*p >> 5) & 0x07; + s->result.t66_seen = TRUE; + span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_t66_to_str(s->result.t66)); return ++p; } /*- End of function --------------------------------------------------------*/ static void ci_decode(v8_state_t *s) { - if ((s->rx_data[0] & 0x1F) == 0x01) + if ((s->rx_data[0] & 0x1F) == V8_CALL_FUNCTION_TAG) process_call_function(s, &s->rx_data[0]); } /*- End of function --------------------------------------------------------*/ @@ -333,57 +403,60 @@ static void cm_jm_decode(v8_state_t *s) return; /* We must receive two consecutive identical CM or JM sequences to accept it. */ - if (s->cm_jm_count <= 0 + if (s->cm_jm_len <= 0 || - s->cm_jm_count != s->rx_data_ptr + s->cm_jm_len != s->rx_data_ptr || memcmp(s->cm_jm_data, s->rx_data, s->rx_data_ptr)) { /* Save the current CM or JM sequence */ - s->cm_jm_count = s->rx_data_ptr; + s->cm_jm_len = s->rx_data_ptr; memcpy(s->cm_jm_data, s->rx_data, s->rx_data_ptr); return; } - /* We have a pair of matching CMs or JMs */ + /* We have a matching pair of CMs or JMs, so we are happy this is correct. */ s->got_cm_jm = TRUE; span_log(&s->logging, SPAN_LOG_FLOW, "Decoding\n"); /* Zero indicates the end */ - s->cm_jm_data[s->cm_jm_count] = 0; + s->cm_jm_data[s->cm_jm_len] = 0; - s->far_end_modulations = 0; + s->result.far_end_modulations = 0; p = s->cm_jm_data; while (*p) { switch (*p & 0x1F) { - case 0x01: + case V8_CALL_FUNCTION_TAG: p = process_call_function(s, p); break; - case 0x05: + case V8_MODULATION_TAG: p = process_modulation_mode(s, p); break; - case 0x0A: + case V8_PROTOCOLS_TAG: p = process_protocols(s, p); break; - case 0x0D: + case V8_PSTN_ACCESS_TAG: p = process_pstn_access(s, p); break; - case 0x0F: + case V8_NSF_TAG: p = process_non_standard_facilities(s, p); break; - case 0x07: + case V8_PCM_MODEM_AVAILABILITY_TAG: p = process_pcm_modem_availability(s, p); break; - case 0x0E: + case V8_T66_TAG: p = process_t66(s, p); break; default: p++; break; } + /* Skip any future extensions we do not understand */ + while ((*p & 0x38) == 0x10) + p++; } } /*- End of function --------------------------------------------------------*/ @@ -411,43 +484,60 @@ static void put_bit(void *user_data, int bit) } return; } + //span_log(&s->logging, SPAN_LOG_FLOW, "Bit %d\n", bit); /* Wait until we sync. */ s->bit_stream = (s->bit_stream >> 1) | (bit << 19); - if (s->bit_stream == 0x803FF) - new_preamble_type = V8_SYNC_CI; - else if (s->bit_stream == 0xF03FF) - new_preamble_type = V8_SYNC_CM_JM; - else if (s->bit_stream == 0xAABFF) - new_preamble_type = V8_SYNC_V92; - else - new_preamble_type = V8_SYNC_UNKNOWN; - if (new_preamble_type) + /* CI preamble is 10 ones then a framed 0x00 + CM/JM preamble is 10 ones then a framed 0x07 + V.92 preamble is 10 ones then a framed 0x55 + Should we look at all 10 ones? The first couple might be + settling down. */ + /* The preamble + synchronisation bit sequence should be unique in + any bit stream, so we can rely on seeing this at any time as being + a real sync code. */ + switch (s->bit_stream) { + case 0x803FF: + new_preamble_type = V8_SYNC_CI; + break; + case 0xF03FF: + new_preamble_type = V8_SYNC_CM_JM; + break; + case 0xAABFF: + new_preamble_type = V8_SYNC_V92; + break; + default: + new_preamble_type = V8_SYNC_UNKNOWN; + break; + } + if (new_preamble_type != V8_SYNC_UNKNOWN) + { + /* We have seen a fresh sync code */ /* Debug */ if (span_log_test(&s->logging, SPAN_LOG_FLOW)) { - if (s->preamble_type == V8_SYNC_CI) + if (s->preamble_type != V8_SYNC_UNKNOWN) { - tag = "CI: "; + switch (s->preamble_type) + { + case V8_SYNC_CI: + tag = "CI: "; + break; + case V8_SYNC_CM_JM: + tag = (s->calling_party) ? "JM: " : "CM: "; + break; + case V8_SYNC_V92: + tag = "V92: "; + break; + default: + tag = "??: "; + break; + } + span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, s->rx_data, s->rx_data_ptr); } - else if (s->preamble_type == V8_SYNC_CM_JM) - { - if (s->caller) - tag = "JM: "; - else - tag = "CM: "; - } - else if (s->preamble_type == V8_SYNC_V92) - { - tag = "V92: "; - } - else - { - tag = "??: "; - } - span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, s->rx_data, s->rx_data_ptr); } - /* Decode previous sequence */ + /* If we were handling a valid sync code then we should process what has been + received to date. */ switch (s->preamble_type) { case V8_SYNC_CI: @@ -462,16 +552,16 @@ static void put_bit(void *user_data, int bit) s->rx_data_ptr = 0; } - /* Parse octets with 1 bit start, 1 bit stop */ - if (s->preamble_type) + if (s->preamble_type != V8_SYNC_UNKNOWN) { + /* Parse octets with 1 bit start, 1 bit stop */ s->bit_cnt++; /* Start, stop? */ if ((s->bit_stream & 0x80400) == 0x80000 && s->bit_cnt >= 10) { /* Store the available data */ data = (uint8_t) ((s->bit_stream >> 11) & 0xFF); - /* CJ detection */ + /* CJ (3 successive zero octets) detection */ if (data == 0) { if (++s->zero_byte_count == 3) @@ -492,13 +582,14 @@ static void put_bit(void *user_data, int bit) static void v8_decode_init(v8_state_t *s) { - if (s->caller) - fsk_rx_init(&s->v21rx, &preset_fsk_specs[FSK_V21CH2], FALSE, put_bit, s); - else - fsk_rx_init(&s->v21rx, &preset_fsk_specs[FSK_V21CH1], FALSE, put_bit, s); - s->preamble_type = 0; + fsk_rx_init(&s->v21rx, + &preset_fsk_specs[(s->calling_party) ? FSK_V21CH2 : FSK_V21CH1], + FSK_FRAME_MODE_ASYNC, + put_bit, + s); + s->preamble_type = V8_SYNC_UNKNOWN; s->bit_stream = 0; - s->cm_jm_count = 0; + s->cm_jm_len = 0; s->got_cm_jm = FALSE; s->got_cj = FALSE; s->zero_byte_count = 0; @@ -513,11 +604,22 @@ static int get_bit(void *user_data) s = user_data; if (queue_read(s->tx_queue, &bit, 1) <= 0) - bit = 1; + return SIG_STATUS_END_OF_DATA; return bit; } /*- End of function --------------------------------------------------------*/ +static void v8_put_preamble(v8_state_t *s) +{ + static const uint8_t preamble[10] = + { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + + queue_write(s->tx_queue, preamble, 10); +} +/*- End of function --------------------------------------------------------*/ + static void v8_put_byte(v8_state_t *s, int data) { int i; @@ -538,17 +640,12 @@ static void v8_put_byte(v8_state_t *s, int data) static void send_cm_jm(v8_state_t *s, int mod_mask) { int val; - static const uint8_t preamble[20] = - { - /* 10 1's (0x3FF), then 10 bits of CM sync (0x00F) */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 - }; /* Send a CM, or a JM as appropriate */ - queue_write(s->tx_queue, preamble, 20); - + v8_put_preamble(s); + v8_put_byte(s, V8_CM_JM_SYNC_OCTET); /* Data call */ - v8_put_byte(s, (V8_CALL_V_SERIES << 5) | 0x01); + v8_put_byte(s, (V8_CALL_V_SERIES << 5) | V8_CALL_FUNCTION_TAG); /* Supported modulations */ val = 0x05; @@ -584,12 +681,12 @@ static void send_cm_jm(v8_state_t *s, int mod_mask) val |= 0x80; v8_put_byte(s, val); - v8_put_byte(s, (0 << 5) | 0x07); + v8_put_byte(s, (0 << 5) | V8_PCM_MODEM_AVAILABILITY_TAG); - v8_put_byte(s, (V8_PROTOCOL_LAPM_V42 << 5) | 0x0A); + v8_put_byte(s, (V8_PROTOCOL_LAPM_V42 << 5) | V8_PROTOCOLS_TAG); /* No cellular right now */ - v8_put_byte(s, (0 << 5) | 0x0D); + v8_put_byte(s, (0 << 5) | V8_PSTN_ACCESS_TAG); } /*- End of function --------------------------------------------------------*/ @@ -615,75 +712,122 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len) //span_log(&s->logging, SPAN_LOG_FLOW, "v8_tx state %d\n", s->state); len = 0; - switch (s->state) + if (s->modem_connect_tone_tx_on) { - case V8_CI_ON: - case V8_CM_ON: - case V8_JM_ON: - case V8_CJ_ON: - len = fsk_tx(&s->v21tx, amp, max_len); - break; - case V8_CM_WAIT: - /* Send the ANSam tone */ - len = modem_connect_tones_tx(&s->ansam_tx, amp, max_len); - break; + if (s->modem_connect_tone_tx_on > ms_to_samples(75)) + { + /* Send the ANSam tone */ + len = modem_connect_tones_tx(&s->ansam_tx, amp, max_len); + if (len < max_len) + { + span_log(&s->logging, SPAN_LOG_FLOW, "ANSam or ANSam/ ended\n"); + s->modem_connect_tone_tx_on = ms_to_samples(75); + } + } + else + { + if (max_len > s->modem_connect_tone_tx_on) + len = s->modem_connect_tone_tx_on; + else + len = max_len; + vec_zeroi16(amp, len); + s->modem_connect_tone_tx_on -= len; + } + } + if (s->fsk_tx_on && len < max_len) + { + max_len -= len; + len = fsk_tx(&s->v21tx, amp + len, max_len); + if (len < max_len) + { + span_log(&s->logging, SPAN_LOG_FLOW, "FSK ends\n"); + s->fsk_tx_on = FALSE; + } } return len; } /*- End of function --------------------------------------------------------*/ +static void v8_send_ci(v8_state_t *s) +{ + int i; + + /* Send 4 CI packets in a burst (the spec says at least 3) */ + for (i = 0; i < 4; i++) + { + v8_put_preamble(s); + v8_put_byte(s, V8_CI_SYNC_OCTET); + v8_put_byte(s, (V8_CALL_V_SERIES << 5) | V8_CALL_FUNCTION_TAG); + } +} +/*- End of function --------------------------------------------------------*/ + +static void handle_modem_connect_tone(v8_state_t *s, int tone) +{ + s->result.modem_connect_tone_detected = tone; + span_log(&s->logging, SPAN_LOG_FLOW, "'%s' recognised\n", modem_connect_tone_to_str(tone)); + if (tone == MODEM_CONNECT_TONES_ANSAM + || + tone == MODEM_CONNECT_TONES_ANSAM_PR) + { + /* Set the Te interval. The spec. says 500ms is the minimum, + but gives reasons why 1 second is a better value. */ + s->state = V8_HEARD_ANSAM; + s->ci_timer = ms_to_samples(1000); + } + else + { + /* If we found a connect tone, and it isn't one of the modulated answer tones, + indicating V.8 startup, we are not going to do V.8 processing. */ + span_log(&s->logging, SPAN_LOG_FLOW, "Non-V.8 modem connect tone detected\n"); + s->state = V8_PARKED; + if (s->result_handler) + s->result_handler(s->result_handler_user_data, &s->result); + } +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) { int i; int residual_samples; - v8_result_t result; - static const uint8_t preamble[20] = - { - /* 10 1's (0x3FF), then 10 bits of CI sync (0x001) */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 - }; + int tone; //span_log(&s->logging, SPAN_LOG_FLOW, "v8_rx state %d\n", s->state); residual_samples = 0; switch (s->state) { case V8_WAIT_1S: + residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); /* Wait 1 second before sending the first CI packet */ if ((s->negotiation_timer -= len) > 0) break; - s->state = V8_CI; - s->ci_count = 0; - modem_connect_tones_rx_init(&s->ansam_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); - fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH1], get_bit, s); - /* Fall through to the next state */ - case V8_CI: - residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); - /* Send 4 CI packets in a burst (the spec says at least 3) */ - for (i = 0; i < 4; i++) - { - /* 10 1's (0x3FF), then CI sync (0x001) */ - queue_write(s->tx_queue, preamble, 20); - v8_put_byte(s, (V8_CALL_V_SERIES << 5) | 0x01); - } + fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); + v8_send_ci(s); s->state = V8_CI_ON; + s->fsk_tx_on = TRUE; break; case V8_CI_ON: residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); + /* Check if an ANSam or ANSam/ tone has been detected */ + if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE) + { + handle_modem_connect_tone(s, tone); + break; + } if (queue_empty(s->tx_queue)) { s->state = V8_CI_OFF; s->ci_timer = ms_to_samples(500); + break; } break; case V8_CI_OFF: residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); - /* Check if an ANSam tone has been detected */ - if (modem_connect_tones_rx_get(&s->ansam_rx)) + /* Check if an ANSam or ANSam/ tone has been detected */ + if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE) { - /* Set the Te interval. The spec. says 500ms is the minimum, - but gives reasons why 1 second is a better value. */ - s->ci_timer = ms_to_samples(1000); - s->state = V8_HEARD_ANSAM; + handle_modem_connect_tone(s, tone); break; } if ((s->ci_timer -= len) <= 0) @@ -691,6 +835,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) if (++s->ci_count >= 10) { /* The spec says we should give up now. */ + span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for modem connect tone\n"); s->state = V8_PARKED; if (s->result_handler) s->result_handler(s->result_handler_user_data, NULL); @@ -698,46 +843,54 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) else { /* Try again */ - s->state = V8_CI; + fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); + v8_send_ci(s); + s->state = V8_CI_ON; + s->fsk_tx_on = TRUE; } } break; case V8_HEARD_ANSAM: - /* We have heard the ANSam signal, but we still need to wait for the + /* We have heard the ANSam or ANSam/ signal, but we still need to wait for the end of the Te timeout period to comply with the spec. */ if ((s->ci_timer -= len) <= 0) { v8_decode_init(s); - s->state = V8_CM_ON; s->negotiation_timer = ms_to_samples(5000); - send_cm_jm(s, s->available_modulations); + fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); + send_cm_jm(s, s->local_end_modulations); + s->state = V8_CM_ON; + s->fsk_tx_on = TRUE; } break; case V8_CM_ON: residual_samples = fsk_rx(&s->v21rx, amp, len); if (s->got_cm_jm) { - /* Now JM has been detected we send CJ and wait for 75 ms + span_log(&s->logging, SPAN_LOG_FLOW, "JM recognised\n"); + /* Now JM has been detected, we send CJ and wait for 75 ms before finishing the V.8 analysis. */ - s->negotiated_modulation = select_modulation(s->far_end_modulations); + s->result.negotiated_modulation = select_modulation(s->result.far_end_modulations); - queue_flush(s->tx_queue); - for (i = 0; i < 9; i++) + fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); + for (i = 0; i < 3; i++) v8_put_byte(s, 0); s->state = V8_CJ_ON; + s->fsk_tx_on = TRUE; break; } if ((s->negotiation_timer -= len) <= 0) { /* Timeout */ + span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for JM\n"); s->state = V8_PARKED; if (s->result_handler) s->result_handler(s->result_handler_user_data, NULL); } - if (queue_empty(s->tx_queue)) + if (queue_contents(s->tx_queue) < 10) { /* Send CM again */ - send_cm_jm(s, s->available_modulations); + send_cm_jm(s, s->local_end_modulations); } break; case V8_CJ_ON: @@ -752,49 +905,33 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) if ((s->negotiation_timer -= len) <= 0) { /* The V.8 negotiation has succeeded. */ + span_log(&s->logging, SPAN_LOG_FLOW, "Negotiation succeeded\n"); s->state = V8_PARKED; if (s->result_handler) - { - result.call_function = s->call_function; - result.available_modulations = s->far_end_modulations; - result.negotiated_modulation = s->negotiated_modulation; - result.protocol = s->protocol; - result.pstn_access = s->pstn_access; - result.nsf_seen = s->nsf_seen; - result.pcm_modem_availability = s->pcm_modem_availability; - result.t66_seen = s->t66_seen; - s->result_handler(s->result_handler_user_data, &result); - } - } - break; - case V8_WAIT_200MS: - if ((s->negotiation_timer -= len) <= 0) - { - /* Send the ANSam tone */ - modem_connect_tones_tx_init(&s->ansam_tx, MODEM_CONNECT_TONES_ANSAM_PR); - - v8_decode_init(s); - s->state = V8_CM_WAIT; - s->negotiation_timer = ms_to_samples(5000); + s->result_handler(s->result_handler_user_data, &s->result); } break; case V8_CM_WAIT: residual_samples = fsk_rx(&s->v21rx, amp, len); if (s->got_cm_jm) { - /* Stop sending ANSam and send JM instead */ + span_log(&s->logging, SPAN_LOG_FLOW, "CM recognised\n"); + /* Stop sending ANSam or ANSam/ and send JM instead */ fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH2], get_bit, s); /* Set the timeout for JM */ s->negotiation_timer = ms_to_samples(5000); s->state = V8_JM_ON; - s->common_modulations = s->available_modulations & s->far_end_modulations; - s->negotiated_modulation = select_modulation(s->common_modulations); + s->common_modulations = s->local_end_modulations & s->result.far_end_modulations; + s->result.negotiated_modulation = select_modulation(s->common_modulations); send_cm_jm(s, s->common_modulations); + s->modem_connect_tone_tx_on = ms_to_samples(75); + s->fsk_tx_on = TRUE; break; } if ((s->negotiation_timer -= len) <= 0) { /* Timeout */ + span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for CM\n"); s->state = V8_PARKED; if (s->result_handler) s->result_handler(s->result_handler_user_data, NULL); @@ -804,7 +941,9 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) residual_samples = fsk_rx(&s->v21rx, amp, len); if (s->got_cj) { - /* Stop sending JM, and wait 75 ms */ + span_log(&s->logging, SPAN_LOG_FLOW, "CJ recognised\n"); + /* Stop sending JM, flushing anything left in the buffer, and wait 75 ms */ + queue_flush(s->tx_queue); s->negotiation_timer = ms_to_samples(75); s->state = V8_SIGA; break; @@ -812,12 +951,13 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) if ((s->negotiation_timer -= len) <= 0) { /* Timeout */ + span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for CJ\n"); s->state = V8_PARKED; if (s->result_handler) s->result_handler(s->result_handler_user_data, NULL); break; } - if (queue_empty(s->tx_queue)) + if (queue_contents(s->tx_queue) < 10) { /* Send JM */ send_cm_jm(s, s->common_modulations); @@ -827,19 +967,10 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) if ((s->negotiation_timer -= len) <= 0) { /* The V.8 negotiation has succeeded. */ + span_log(&s->logging, SPAN_LOG_FLOW, "Negotiation succeeded\n"); s->state = V8_PARKED; if (s->result_handler) - { - result.call_function = s->call_function; - result.available_modulations = s->far_end_modulations; - result.negotiated_modulation = s->negotiated_modulation; - result.protocol = s->protocol; - result.pstn_access = s->pstn_access; - result.nsf_seen = s->nsf_seen; - result.pcm_modem_availability = s->pcm_modem_availability; - result.t66_seen = s->t66_seen; - s->result_handler(s->result_handler_user_data, &result); - } + s->result_handler(s->result_handler_user_data, &s->result); } break; case V8_PARKED: @@ -857,7 +988,8 @@ SPAN_DECLARE(logging_state_t *) v8_get_logging_state(v8_state_t *s) /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s, - int caller, + int calling_party, + int use_ansam_pr, int available_modulations, v8_result_handler_t *result_handler, void *user_data) @@ -868,22 +1000,36 @@ SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s, return NULL; } memset(s, 0, sizeof(*s)); - s->caller = caller; - s->available_modulations = available_modulations; + span_log_init(&s->logging, SPAN_LOG_NONE, NULL); + span_log_set_protocol(&s->logging, "V.8"); + s->local_end_modulations = available_modulations; s->result_handler = result_handler; s->result_handler_user_data = user_data; s->ci_timer = 0; - if (s->caller) + if (calling_party) { + s->calling_party = TRUE; s->state = V8_WAIT_1S; s->negotiation_timer = ms_to_samples(1000); + s->ci_count = 0; + modem_connect_tones_rx_init(&s->ansam_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); + fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH1], get_bit, s); } else { - s->state = V8_WAIT_200MS; - s->negotiation_timer = ms_to_samples(200); + /* Send the ANSam or ANSam/ tone */ + s->calling_party = FALSE; + modem_connect_tones_tx_init(&s->ansam_tx, + (use_ansam_pr) ? MODEM_CONNECT_TONES_ANSAM_PR : MODEM_CONNECT_TONES_ANSAM); + + v8_decode_init(s); + s->state = V8_CM_WAIT; + s->negotiation_timer = ms_to_samples(200 + 5000); + s->modem_connect_tone_tx_on = ms_to_samples(75) + 1; } + s->result.modem_connect_tone_detected = MODEM_CONNECT_TONES_NONE; + if ((s->tx_queue = queue_init(NULL, 1024, 0)) == NULL) return NULL; return s; diff --git a/libs/spandsp/tests/at_interpreter_tests.c b/libs/spandsp/tests/at_interpreter_tests.c index af54887c3c..2b63863751 100644 --- a/libs/spandsp/tests/at_interpreter_tests.c +++ b/libs/spandsp/tests/at_interpreter_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: at_interpreter_tests.c,v 1.23 2009/05/30 15:23:13 steveu Exp $ + * $Id: at_interpreter_tests.c,v 1.24 2009/10/09 14:53:57 steveu Exp $ */ /*! \file */ @@ -234,6 +234,9 @@ static const struct command_response_s general_test_seq[] = {"AT+ETBM?\r", "\r\n+ETBM:0,0\r\n\r\nOK\r\n"}, {"AT+EWIND=?\r", "\r\n+EWIND:(1-127),(1-127)\r\n\r\nOK\r\n"}, /* V.250 6.5.7 - Window size */ {"AT+EWIND?\r", "\r\n+EWIND:0,0\r\n\r\nOK\r\n"}, + {"AT+F34=?\r", "\r\n+F34:(0-14),(0-14),(0-2),(0-14),(0-14)\r\n\r\nOK\r\n"}, + /* T.31 B.6.1 - Initial V.34 rate controls for FAX */ + {"AT+F34?\r", "\r\n+F34:0,0,0,0,0\r\n\r\nOK\r\n"}, {"AT+FAR=?\r", "\r\n0,1\r\n\r\nOK\r\n"}, /* T.31 8.5.1 - Adaptive reception control */ {"AT+FAR?\r", "\r\n0\r\n\r\nOK\r\n"}, {"AT+FCL=?\r", "\r\n(0-255)\r\n\r\nOK\r\n"}, /* T.31 8.5.2 - Carrier loss timeout */ diff --git a/libs/spandsp/tests/fax_decode.c b/libs/spandsp/tests/fax_decode.c index ec5a493f4c..4b94adf251 100644 --- a/libs/spandsp/tests/fax_decode.c +++ b/libs/spandsp/tests/fax_decode.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: fax_decode.c,v 1.57 2009/09/15 14:01:53 steveu Exp $ + * $Id: fax_decode.c,v 1.58 2009/11/02 13:25:20 steveu Exp $ */ /*! \page fax_decode_page FAX decoder @@ -479,7 +479,7 @@ int main(int argc, char *argv[]) span_log_set_protocol(&t30_dummy.logging, "T.30"); hdlc_rx_init(&hdlcrx, FALSE, TRUE, 5, hdlc_accept, NULL); - fsk = fsk_rx_init(NULL, &preset_fsk_specs[FSK_V21CH2], TRUE, v21_put_bit, NULL); + fsk = fsk_rx_init(NULL, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, NULL); v17 = v17_rx_init(NULL, 14400, v17_put_bit, NULL); v29 = v29_rx_init(NULL, 9600, v29_put_bit, NULL); //v29 = v29_rx_init(NULL, 7200, v29_put_bit, NULL); diff --git a/libs/spandsp/tests/fax_tester.c b/libs/spandsp/tests/fax_tester.c index 4ce830a32b..0a3ccea7aa 100644 --- a/libs/spandsp/tests/fax_tester.c +++ b/libs/spandsp/tests/fax_tester.c @@ -22,7 +22,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: fax_tester.c,v 1.22 2009/02/12 12:38:39 steveu Exp $ + * $Id: fax_tester.c,v 1.23 2009/11/02 13:25:20 steveu Exp $ */ /*! \file */ @@ -496,7 +496,7 @@ void faxtester_set_rx_type(void *user_data, int type, int bit_rate, int short_tr case T30_MODEM_V21: if (s->flush_handler) s->flush_handler(s, s->flush_user_data, 3); - fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, put_bit_user_data); + fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, put_bit_user_data); fsk_rx_signal_cutoff(&t->v21_rx, -45.5); t->rx_handler = (span_rx_handler_t *) &fsk_rx; t->rx_user_data = &t->v21_rx; @@ -670,7 +670,7 @@ static void faxtester_fax_modems_init(fax_modems_state_t *s, int use_tep, void * hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, user_data); hdlc_tx_init(&s->hdlc_tx, FALSE, 2, FALSE, hdlc_underflow_handler, user_data); - fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx); + fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx); fsk_rx_signal_cutoff(&s->v21_rx, -45.5); fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx); fsk_tx_set_modem_status_handler(&s->v21_tx, modem_tx_status, user_data); diff --git a/libs/spandsp/tests/fax_tests.sh b/libs/spandsp/tests/fax_tests.sh index f95e41c28c..02fb8c7e44 100755 --- a/libs/spandsp/tests/fax_tests.sh +++ b/libs/spandsp/tests/fax_tests.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # spandsp fax tests # diff --git a/libs/spandsp/tests/fax_utils.c b/libs/spandsp/tests/fax_utils.c index e582298b5d..9903109a6b 100644 --- a/libs/spandsp/tests/fax_utils.c +++ b/libs/spandsp/tests/fax_utils.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: fax_utils.c,v 1.3 2009/05/16 03:34:45 steveu Exp $ + * $Id: fax_utils.c,v 1.3.4.1 2009/12/19 09:47:57 steveu Exp $ */ #if defined(HAVE_CONFIG_H) @@ -95,8 +95,8 @@ void log_transfer_statistics(t30_state_t *s, const char *tag) printf("%s: ECM %s\n", tag, (t.error_correcting_mode) ? "on" : "off"); printf("%s: tx pages %d, rx pages %d\n", tag, t.pages_tx, t.pages_rx); printf("%s: pages in the file %d\n", tag, t.pages_in_file); - printf("%s: image size %d x %d\n", tag, t.width, t.length); - printf("%s: image resolution %d x %d\n", tag, t.x_resolution, t.y_resolution); + printf("%s: image size %d pels x %d pels\n", tag, t.width, t.length); + printf("%s: image resolution %d pels/m x %d pels/m\n", tag, t.x_resolution, t.y_resolution); printf("%s: bad rows %d, longest bad row run %d\n", tag, t.bad_rows, t.longest_bad_row_run); printf("%s: bad ECM frames %d\n", tag, t.error_correcting_mode_retries); printf("%s: compression type %d\n", tag, t.encoding); diff --git a/libs/spandsp/tests/fsk_tests.c b/libs/spandsp/tests/fsk_tests.c index 40d83ceb08..57e226e0cf 100644 --- a/libs/spandsp/tests/fsk_tests.c +++ b/libs/spandsp/tests/fsk_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: fsk_tests.c,v 1.58 2009/07/09 13:52:09 steveu Exp $ + * $Id: fsk_tests.c,v 1.59 2009/11/02 13:25:20 steveu Exp $ */ /*! \page fsk_tests_page FSK modem tests @@ -283,7 +283,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); exit(2); } - caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, put_bit, NULL); + caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, put_bit, NULL); fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; @@ -306,7 +306,7 @@ int main(int argc, char *argv[]) else { printf("Test cutoff level\n"); - caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, cutoff_test_put_bit, NULL); + caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, cutoff_test_put_bit, NULL); fsk_rx_signal_cutoff(caller_rx, -30.0f); fsk_rx_set_modem_status_handler(caller_rx, cutoff_test_rx_status, (void *) &caller_rx); on_at = 0; @@ -370,14 +370,14 @@ int main(int argc, char *argv[]) { caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert); fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx); - answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert); + answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &answerer_bert); fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx); } if (modem_under_test_2 >= 0) { answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert); fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx); - caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert); + caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &caller_bert); fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); } test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; @@ -477,14 +477,14 @@ int main(int argc, char *argv[]) { caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert); fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx); - answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert); + answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &answerer_bert); fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx); } if (modem_under_test_2 >= 0) { answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert); fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx); - caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert); + caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &caller_bert); fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); } noise_level++; diff --git a/libs/spandsp/tests/modem_connect_tones_tests.c b/libs/spandsp/tests/modem_connect_tones_tests.c index a33133a58c..e2e7b14037 100644 --- a/libs/spandsp/tests/modem_connect_tones_tests.c +++ b/libs/spandsp/tests/modem_connect_tones_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: modem_connect_tones_tests.c,v 1.30 2009/05/30 15:23:14 steveu Exp $ + * $Id: modem_connect_tones_tests.c,v 1.32 2009/11/02 15:04:15 steveu Exp $ */ /*! \page modem_connect_tones_tests_page Modem connect tones tests @@ -61,11 +61,21 @@ These tests... #define FALSE 0 #define TRUE (!FALSE) -#define LEVEL_MAX 0 +#define LEVEL_MAX -5 #define LEVEL_MIN -48 #define LEVEL_MIN_ACCEPT -43 #define LEVEL_MIN_REJECT -44 +/* The 1100Hz tone is supposed to be within 38Hz, according to T.30. Allow another 8Hz for FDM, even though + you rarely see that used today. */ +#define CED_FREQ_TOLERANCE (38 + 8) +#define CED_FREQ_BLACKOUT (80) +/* The 2100Hz tone is supposed to be within 15Hz, according to T.30. Allow another 8Hz for FDM, even though + you rarely see that used today. */ +#define CNG_FREQ_TOLERANCE (15 + 8) +#define CNG_FREQ_BLACKOUT (80) +#define AM_FREQ_TOLERANCE (1) + const char *bellcore_files[] = { MITEL_DIR "mitel-cm7291-talkoff.wav", @@ -88,13 +98,21 @@ enum PERFORM_TEST_2A = (1 << 6), PERFORM_TEST_2B = (1 << 7), PERFORM_TEST_2C = (1 << 8), - PERFORM_TEST_3A = (1 << 9), - PERFORM_TEST_3B = (1 << 10), - PERFORM_TEST_3C = (1 << 11), - PERFORM_TEST_4 = (1 << 12), - PERFORM_TEST_5A = (1 << 13), - PERFORM_TEST_5B = (1 << 14), - PERFORM_TEST_6 = (1 << 15) + PERFORM_TEST_2D = (1 << 9), + PERFORM_TEST_2E = (1 << 10), + PERFORM_TEST_3A = (1 << 11), + PERFORM_TEST_3B = (1 << 12), + PERFORM_TEST_3C = (1 << 13), + PERFORM_TEST_3D = (1 << 14), + PERFORM_TEST_3E = (1 << 15), + PERFORM_TEST_4 = (1 << 16), + PERFORM_TEST_5A = (1 << 17), + PERFORM_TEST_5B = (1 << 18), + PERFORM_TEST_6A = (1 << 19), + PERFORM_TEST_6B = (1 << 20), + PERFORM_TEST_7A = (1 << 21), + PERFORM_TEST_7B = (1 << 22), + PERFORM_TEST_8 = (1 << 23) }; int preamble_count = 0; @@ -129,10 +147,18 @@ static int preamble_get_bit(void *user_data) } /*- End of function --------------------------------------------------------*/ -static void preamble_detected(void *user_data, int on, int level, int delay) +static void cng_detected(void *user_data, int tone, int level, int delay) { - printf("%s (%d) declared at bit %d (%ddBm0)\n", modem_connect_tone_to_str(on), on, preamble_count, level); - if (on) + printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); + if (tone == MODEM_CONNECT_TONES_FAX_CNG) + hits++; +} +/*- End of function --------------------------------------------------------*/ + +static void preamble_detected(void *user_data, int tone, int level, int delay) +{ + printf("%s (%d) declared at bit %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, preamble_count, level); + if (tone == MODEM_CONNECT_TONES_FAX_PREAMBLE) preamble_on_at = preamble_count; else preamble_off_at = preamble_count; @@ -140,34 +166,22 @@ static void preamble_detected(void *user_data, int on, int level, int delay) } /*- End of function --------------------------------------------------------*/ -static void ced_detected(void *user_data, int on, int level, int delay) +static void ced_detected(void *user_data, int tone, int level, int delay) { - printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(on), on, (float) when/SAMPLE_RATE, delay, level); - if (on) + printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); + if (tone == MODEM_CONNECT_TONES_FAX_PREAMBLE + || + tone == MODEM_CONNECT_TONES_ANS) + { hits++; + } } /*- End of function --------------------------------------------------------*/ -static void ans_pr_detected(void *user_data, int on, int level, int delay) +static void ans_pr_detected(void *user_data, int tone, int level, int delay) { - printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(on), on, (float) when/SAMPLE_RATE, delay, level); - if (on == MODEM_CONNECT_TONES_ANS_PR) - hits++; -} -/*- End of function --------------------------------------------------------*/ - -static void cng_detected(void *user_data, int on, int level, int delay) -{ - printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(on), on, (float) when/SAMPLE_RATE, delay, level); - if (on) - hits++; -} -/*- End of function --------------------------------------------------------*/ - -static void ec_dis_detected(void *user_data, int on, int level, int delay) -{ - printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(on), on, (float) when/SAMPLE_RATE, delay, level); - if (on) + printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); + if (tone == MODEM_CONNECT_TONES_ANS_PR) hits++; } /*- End of function --------------------------------------------------------*/ @@ -177,6 +191,7 @@ int main(int argc, char *argv[]) int i; int j; int pitch; + int depth; int level; int interval; int cycle; @@ -194,13 +209,12 @@ int main(int argc, char *argv[]) int hit; int false_hit; int false_miss; - tone_gen_descriptor_t tone_desc; - tone_gen_state_t tone_tx; power_meter_t power_state; int power; int max_power; int level2; int max_level2; + int tone_type; int test_list; int opt; char *decode_test_file; @@ -241,20 +255,36 @@ int main(int argc, char *argv[]) test_list |= PERFORM_TEST_2B; else if (strcasecmp(argv[i], "2c") == 0) test_list |= PERFORM_TEST_2C; + else if (strcasecmp(argv[i], "2d") == 0) + test_list |= PERFORM_TEST_2D; + else if (strcasecmp(argv[i], "2e") == 0) + test_list |= PERFORM_TEST_2E; else if (strcasecmp(argv[i], "3a") == 0) test_list |= PERFORM_TEST_3A; else if (strcasecmp(argv[i], "3b") == 0) test_list |= PERFORM_TEST_3B; else if (strcasecmp(argv[i], "3c") == 0) test_list |= PERFORM_TEST_3C; + else if (strcasecmp(argv[i], "3d") == 0) + test_list |= PERFORM_TEST_3D; + else if (strcasecmp(argv[i], "3e") == 0) + test_list |= PERFORM_TEST_3E; else if (strcasecmp(argv[i], "4") == 0) test_list |= PERFORM_TEST_4; else if (strcasecmp(argv[i], "5a") == 0) test_list |= PERFORM_TEST_5A; else if (strcasecmp(argv[i], "5b") == 0) test_list |= PERFORM_TEST_5B; - else if (strcasecmp(argv[i], "6") == 0) - test_list |= PERFORM_TEST_6; + else if (strcasecmp(argv[i], "6a") == 0) + test_list |= PERFORM_TEST_6A; + else if (strcasecmp(argv[i], "6b") == 0) + test_list |= PERFORM_TEST_6B; + else if (strcasecmp(argv[i], "7a") == 0) + test_list |= PERFORM_TEST_7A; + else if (strcasecmp(argv[i], "7b") == 0) + test_list |= PERFORM_TEST_7B; + else if (strcasecmp(argv[i], "8") == 0) + test_list |= PERFORM_TEST_8; else { fprintf(stderr, "Unknown test '%s' specified\n", argv[i]); @@ -310,7 +340,7 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_1C)) { - printf("Test 1c: ANSAM (Modulated ANS) generation to a file\n"); + printf("Test 1c: ANSam (Modulated ANS) generation to a file\n"); /* Some with modulation */ modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANSAM); for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) @@ -330,8 +360,8 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_1D)) { - printf("Test 1d: ANS PR (EC-disable) generation to a file\n"); - /* Some without modulation */ + printf("Test 1d: ANS/ (EC-disable) generation to a file\n"); + /* Some without modulation, but with phase reversals */ modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS_PR); for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { @@ -350,8 +380,8 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_1E)) { - printf("Test 1e: ANSAM PR (Modulated EC-disable) generation to a file\n"); - /* Some with modulation */ + printf("Test 1e: ANSam/ (Modulated EC-disable) generation to a file\n"); + /* Some with modulation and phase reversals */ modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANSAM_PR); for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { @@ -378,24 +408,17 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_2A)) { printf("Test 2a: CNG detection with frequency\n"); + tone_type = MODEM_CONNECT_TONES_FAX_CNG; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); false_hit = FALSE; false_miss = FALSE; - for (pitch = 600; pitch < 1600; pitch++) + for (pitch = 600; pitch <= 1600; pitch++) { - make_tone_gen_descriptor(&tone_desc, - pitch, - -11, - 0, - 0, - 425, - 3000, - 0, - 0, - TRUE); - tone_gen_init(&tone_tx, &tone_desc); - - modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL); + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); + modem_connect_tones_rx_init(&cng_rx, tone_type, NULL, NULL); power_meter_init(&power_state, 5); power = 0; max_power = 0; @@ -403,7 +426,7 @@ int main(int argc, char *argv[]) max_level2 = 0; for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { - samples = tone_gen(&tone_tx, amp, SAMPLES_PER_CHUNK); + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); for (j = 0; j < samples; j++) { amp[j] += awgn(&chan_noise_source); @@ -420,21 +443,21 @@ int main(int argc, char *argv[]) } /*endfor*/ hit = modem_connect_tones_rx_get(&cng_rx); - if (pitch < (1100 - 70) || pitch > (1100 + 70)) + if (pitch < (1100 - CED_FREQ_BLACKOUT) || pitch > (1100 + CED_FREQ_BLACKOUT)) { - if (hit == MODEM_CONNECT_TONES_FAX_CNG) + if (hit != MODEM_CONNECT_TONES_NONE) false_hit = TRUE; /*endif*/ } - else if (pitch > (1100 - 50) && pitch < (1100 + 50)) + else if (pitch > (1100 - CED_FREQ_TOLERANCE) && pitch < (1100 + CED_FREQ_TOLERANCE)) { - if (hit != MODEM_CONNECT_TONES_FAX_CNG) + if (hit != tone_type) false_miss = TRUE; /*endif*/ } /*endif*/ - if (hit) - printf("Detected at %5dHz %12d %12d %d\n", pitch, cng_rx.channel_level, cng_rx.notch_level, hit); + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, cng_rx.channel_level, cng_rx.notch_level, hit); /*endif*/ } /*endfor*/ @@ -447,7 +470,7 @@ int main(int argc, char *argv[]) printf("Test passed.\n"); } /*endif*/ - + if ((test_list & PERFORM_TEST_2B)) { printf("Test 2b: CED/ANS detection with frequency\n"); @@ -456,22 +479,14 @@ int main(int argc, char *argv[]) false_miss = FALSE; for (pitch = 1600; pitch < 2600; pitch++) { - make_tone_gen_descriptor(&tone_desc, - pitch, - -11, - 0, - 0, - 2600, - 0, - 0, - 0, - FALSE); - tone_gen_init(&tone_tx, &tone_desc); - + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS); + /* Fudge things for the test */ + modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { - samples = tone_gen(&tone_tx, amp, SAMPLES_PER_CHUNK); + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); for (j = 0; j < samples; j++) amp[j] += awgn(&chan_noise_source); /*endfor*/ @@ -479,19 +494,21 @@ int main(int argc, char *argv[]) } /*endfor*/ hit = modem_connect_tones_rx_get(&ced_rx); - if (pitch < (2100 - 70) || pitch > (2100 + 70)) + if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) { - if (hit == MODEM_CONNECT_TONES_FAX_CED) + if (hit != MODEM_CONNECT_TONES_NONE) false_hit = TRUE; + /*endif*/ } - else if (pitch > (2100 - 50) && pitch < (2100 + 50)) + else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) { if (hit != MODEM_CONNECT_TONES_FAX_CED) false_miss = TRUE; + /*endif*/ } /*endif*/ - if (hit) - printf("Detected at %5dHz %12d %12d %d\n", pitch, ced_rx.channel_level, ced_rx.notch_level, hit); + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ced_rx.channel_level, ced_rx.notch_level, hit); /*endif*/ } if (false_hit || false_miss) @@ -506,18 +523,18 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_2C)) { - printf("Test 2c: EC disable detection with frequency\n"); + printf("Test 2c: ANSam detection with frequency\n"); + tone_type = MODEM_CONNECT_TONES_ANSAM; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); false_hit = FALSE; false_miss = FALSE; - for (pitch = 2000; pitch < 2200; pitch++) + for (pitch = 2000; pitch <= 2200; pitch++) { /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS_PR); + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); /* Fudge things for the test */ modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(-25); - modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); @@ -528,21 +545,125 @@ int main(int argc, char *argv[]) } /*endfor*/ hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (pitch < (2100 - 70) || pitch > (2100 + 70)) + if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) { - if (hit == MODEM_CONNECT_TONES_ANS_PR) + if (hit != MODEM_CONNECT_TONES_NONE) false_hit = TRUE; /*endif*/ } - else if (pitch > (2100 - 50) && pitch < (2100 + 50)) + else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) { - if (hit != MODEM_CONNECT_TONES_ANS_PR) + if (hit != tone_type) false_miss = TRUE; /*endif*/ } /*endif*/ - if (hit) - printf("Detected at %5dHz %12d %12d %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + /*endif*/ + } + /*endfor*/ + if (false_hit || false_miss) + { + printf("Test failed.\n"); + exit(2); + } + /*endif*/ + printf("Test passed.\n"); + } + /*endif*/ + + if ((test_list & PERFORM_TEST_2D)) + { + printf("Test 2d: ANS/ (EC-disable) detection with frequency\n"); + tone_type = MODEM_CONNECT_TONES_ANS_PR; + awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); + false_hit = FALSE; + false_miss = FALSE; + for (pitch = 2000; pitch <= 2200; pitch++) + { + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); + for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) + { + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); + for (j = 0; j < samples; j++) + amp[j] += awgn(&chan_noise_source); + /*endfor*/ + modem_connect_tones_rx(&ans_pr_rx, amp, samples); + } + /*endfor*/ + hit = modem_connect_tones_rx_get(&ans_pr_rx); + if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) + { + if (hit != MODEM_CONNECT_TONES_NONE) + false_hit = TRUE; + /*endif*/ + } + else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) + { + if (hit != tone_type) + false_miss = TRUE; + /*endif*/ + } + /*endif*/ + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + /*endif*/ + } + /*endfor*/ + if (false_hit || false_miss) + { + printf("Test failed.\n"); + exit(2); + } + /*endif*/ + printf("Test passed.\n"); + } + /*endif*/ + + if ((test_list & PERFORM_TEST_2E)) + { + printf("Test 2e: ANSam/ (Modulated EC-disable) detection with frequency\n"); + tone_type = MODEM_CONNECT_TONES_ANSAM_PR; + awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); + false_hit = FALSE; + false_miss = FALSE; + for (pitch = 2000; pitch <= 2200; pitch++) + { + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); + for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) + { + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); + for (j = 0; j < samples; j++) + amp[j] += awgn(&chan_noise_source); + /*endfor*/ + modem_connect_tones_rx(&ans_pr_rx, amp, samples); + } + /*endfor*/ + hit = modem_connect_tones_rx_get(&ans_pr_rx); + if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) + { + if (hit != MODEM_CONNECT_TONES_NONE) + false_hit = TRUE; + /*endif*/ + } + else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) + { + if (hit != tone_type) + false_miss = TRUE; + /*endif*/ + } + /*endif*/ + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); /*endif*/ } /*endfor*/ @@ -559,29 +680,23 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_3A)) { printf("Test 3a: CNG detection with level\n"); + tone_type = MODEM_CONNECT_TONES_FAX_CNG; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); false_hit = FALSE; false_miss = FALSE; - for (pitch = 1062; pitch <= 1138; pitch += 2*38) + for (pitch = 1100 - CED_FREQ_TOLERANCE; pitch <= 1100 + CED_FREQ_TOLERANCE; pitch += 2*CED_FREQ_TOLERANCE) { for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) { - make_tone_gen_descriptor(&tone_desc, - pitch, - level, - 0, - 0, - 500, - 3000, - 0, - 0, - TRUE); - tone_gen_init(&tone_tx, &tone_desc); - - modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL); + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); + modem_tone_tx.level = dds_scaling_dbm0(level); + modem_connect_tones_rx_init(&cng_rx, tone_type, NULL, NULL); for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { - samples = tone_gen(&tone_tx, amp, SAMPLES_PER_CHUNK); + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); for (j = 0; j < samples; j++) amp[j] += awgn(&chan_noise_source); /*endfor*/ @@ -591,25 +706,19 @@ int main(int argc, char *argv[]) hit = modem_connect_tones_rx_get(&cng_rx); if (level < LEVEL_MIN_REJECT) { - if (hit == MODEM_CONNECT_TONES_FAX_CNG) - { - printf("False hit %d at %ddB\n", hit, level); + if (hit != MODEM_CONNECT_TONES_NONE) false_hit = TRUE; - } /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { - if (hit != MODEM_CONNECT_TONES_FAX_CNG) - { - printf("False miss %d at %ddB\n", hit, level); + if (hit != tone_type) false_miss = TRUE; - } /*endif*/ } /*endif*/ - if (hit) - printf("Detected at %5dHz %4ddB %12d %12d %d\n", pitch, level, cng_rx.channel_level, cng_rx.notch_level, hit); + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, cng_rx.channel_level, cng_rx.notch_level, hit); /*endif*/ } /*endfor*/ @@ -628,28 +737,23 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_3B)) { printf("Test 3b: CED/ANS detection with level\n"); + tone_type = MODEM_CONNECT_TONES_ANS; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); false_hit = FALSE; false_miss = FALSE; - for (pitch = 2062; pitch <= 2138; pitch += 2*38) + for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) { for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) { - make_tone_gen_descriptor(&tone_desc, - pitch, - level, - 0, - 0, - 2600, - 0, - 0, - 0, - FALSE); - tone_gen_init(&tone_tx, &tone_desc); + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); + modem_tone_tx.level = dds_scaling_dbm0(level); modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { - samples = tone_gen(&tone_tx, amp, SAMPLES_PER_CHUNK); + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); for (j = 0; j < samples; j++) amp[j] += awgn(&chan_noise_source); /*endfor*/ @@ -659,19 +763,19 @@ int main(int argc, char *argv[]) hit = modem_connect_tones_rx_get(&ced_rx); if (level < LEVEL_MIN_REJECT) { - if (hit == MODEM_CONNECT_TONES_FAX_CED) + if (hit != MODEM_CONNECT_TONES_NONE) false_hit = TRUE; /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { - if (hit != MODEM_CONNECT_TONES_FAX_CED) + if (hit != tone_type) false_miss = TRUE; /*endif*/ } /*endif*/ - if (hit) - printf("Detected at %5dHz %4ddB %12d %12d %d\n", pitch, level, ced_rx.channel_level, ced_rx.notch_level, hit); + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, ced_rx.channel_level, ced_rx.notch_level, hit); /*endif*/ } /*endfor*/ @@ -689,20 +793,23 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_3C)) { - printf("Test 3c: EC disable detection with level\n"); + printf("Test 3c: ANSam detection with level\n"); + tone_type = MODEM_CONNECT_TONES_ANSAM; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); false_hit = FALSE; false_miss = FALSE; - for (pitch = 2062; pitch <= 2138; pitch += 2*38) + for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) { - for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) + //for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) + for (level = -26; level >= -26; level--) { /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS_PR); + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); /* Fudge things for the test */ modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); modem_tone_tx.level = dds_scaling_dbm0(level); - modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); + modem_tone_tx.mod_level = modem_tone_tx.level*20/100; + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); @@ -715,19 +822,134 @@ int main(int argc, char *argv[]) hit = modem_connect_tones_rx_get(&ans_pr_rx); if (level < LEVEL_MIN_REJECT) { - if (hit == MODEM_CONNECT_TONES_ANS_PR) + if (hit != MODEM_CONNECT_TONES_NONE) false_hit = TRUE; /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { - if (hit != MODEM_CONNECT_TONES_ANS_PR) + if (hit != tone_type) false_miss = TRUE; /*endif*/ } /*endif*/ - if (hit) - printf("Detected at %5dHz %4ddB %12d %12d %d\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + //if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + /*endif*/ + } + /*endfor*/ + } + /*endfor*/ + if (false_hit || false_miss) + { + printf("Test failed.\n"); + exit(2); + } + /*endif*/ + printf("Test passed.\n"); + } + /*endif*/ + + if ((test_list & PERFORM_TEST_3D)) + { + printf("Test 3d: ANS/ (EC-disable) detection with level\n"); + tone_type = MODEM_CONNECT_TONES_ANS_PR; + awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); + false_hit = FALSE; + false_miss = FALSE; + for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) + { + for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) + { + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); + modem_tone_tx.level = dds_scaling_dbm0(level); + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); + for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) + { + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); + for (j = 0; j < samples; j++) + amp[j] += awgn(&chan_noise_source); + /*endfor*/ + modem_connect_tones_rx(&ans_pr_rx, amp, samples); + } + /*endfor*/ + hit = modem_connect_tones_rx_get(&ans_pr_rx); + if (level < LEVEL_MIN_REJECT) + { + if (hit != MODEM_CONNECT_TONES_NONE) + false_hit = TRUE; + /*endif*/ + } + else if (level > LEVEL_MIN_ACCEPT) + { + if (hit != tone_type) + false_miss = TRUE; + /*endif*/ + } + /*endif*/ + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + /*endif*/ + } + /*endfor*/ + } + /*endfor*/ + if (false_hit || false_miss) + { + printf("Test failed.\n"); + exit(2); + } + /*endif*/ + printf("Test passed.\n"); + } + /*endif*/ + + if ((test_list & PERFORM_TEST_3E)) + { + printf("Test 3e: ANSam/ (Modulated EC-disable) detection with level\n"); + tone_type = MODEM_CONNECT_TONES_ANSAM_PR; + awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); + false_hit = FALSE; + false_miss = FALSE; + for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) + { + for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) + { + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); + modem_tone_tx.level = dds_scaling_dbm0(level); + modem_tone_tx.mod_level = modem_tone_tx.level*20/100; + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); + for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) + { + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); + for (j = 0; j < samples; j++) + amp[j] += awgn(&chan_noise_source); + /*endfor*/ + modem_connect_tones_rx(&ans_pr_rx, amp, samples); + } + /*endfor*/ + hit = modem_connect_tones_rx_get(&ans_pr_rx); + if (level < LEVEL_MIN_REJECT) + { + if (hit != MODEM_CONNECT_TONES_NONE) + false_hit = TRUE; + /*endif*/ + } + else if (level > LEVEL_MIN_ACCEPT) + { + if (hit != tone_type) + false_miss = TRUE; + /*endif*/ + } + /*endif*/ + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); /*endif*/ } /*endfor*/ @@ -779,21 +1001,17 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_5A)) { - printf("Test 5A: ANS/ANS PR detection with reversal interval\n"); + printf("Test 5A: ANS and ANS/ detection with reversal interval\n"); + tone_type = MODEM_CONNECT_TONES_ANS_PR; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); false_hit = FALSE; false_miss = FALSE; - pitch = 2100; - level = -15; for (interval = 400; interval < 800; interval++) { printf("Reversal interval = %d\n", interval); /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS_PR); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(level); - modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, ans_pr_detected, NULL); + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, ans_pr_detected, NULL); hits = 0; for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { @@ -829,7 +1047,7 @@ int main(int argc, char *argv[]) } /*endif*/ if (hits) - printf("Detected at %5dHz %4ddB %dms %12d %12d %d\n", pitch, level, interval, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hits); + printf("Detected at %5dHz %4ddB %dms %12" PRId32 " %12" PRId32 " %d\n", 2100, -11, interval, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hits); /*endif*/ } /*endfor*/ @@ -845,22 +1063,18 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_5B)) { - printf("Test 5B: ANS/ANS PR detection with mixed reversal intervals\n"); + printf("Test 5B: ANS and ANS/ detection with mixed reversal intervals\n"); awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); + tone_type = MODEM_CONNECT_TONES_ANS_PR; false_hit = FALSE; false_miss = FALSE; - pitch = 2100; - level = -15; interval = 450; printf("Reversal interval = %d\n", interval); /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS_PR); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(level); - modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, ans_pr_detected, NULL); - hits = 0; + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, ans_pr_detected, NULL); cycle = 0; + hits = 0; for (i = 0; i < 60*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) { when = i; @@ -883,6 +1097,7 @@ int main(int argc, char *argv[]) amp[j] += awgn(&chan_noise_source); /*endfor*/ modem_connect_tones_rx(&ans_pr_rx, amp, samples); + /* TODO: Add test result detection logic. */ } /*endfor*/ if (false_hit || false_miss) @@ -895,7 +1110,217 @@ int main(int argc, char *argv[]) } /*endif*/ - if ((test_list & PERFORM_TEST_6)) + if ((test_list & PERFORM_TEST_6A)) + { + printf("Test 6a: ANSam detection with AM pitch\n"); + tone_type = MODEM_CONNECT_TONES_ANSAM; + awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); + false_hit = FALSE; + false_miss = FALSE; + for (pitch = 5; pitch < 25; pitch++) + { + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.mod_phase_rate = dds_phase_rate(pitch); + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); + for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) + { + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); + for (j = 0; j < samples; j++) + amp[j] += awgn(&chan_noise_source); + /*endfor*/ + modem_connect_tones_rx(&ans_pr_rx, amp, samples); + } + /*endfor*/ + hit = modem_connect_tones_rx_get(&ans_pr_rx); + if (pitch < (15 - 10) || pitch > (15 + 10)) + { + if (hit == tone_type) + false_hit = TRUE; + /*endif*/ + } + else if (pitch > (15 - AM_FREQ_TOLERANCE) && pitch < (15 + AM_FREQ_TOLERANCE)) + { + if (hit != tone_type) + false_miss = TRUE; + /*endif*/ + } + /*endif*/ + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + /*endif*/ + } + /*endfor*/ + if (false_hit || false_miss) + { + printf("Test failed.\n"); + exit(2); + } + /*endif*/ + printf("Test passed.\n"); + } + /*endif*/ + + if ((test_list & PERFORM_TEST_6B)) + { + printf("Test 6b: ANSam/ (Modulated EC-disable) detection with AM pitch\n"); + tone_type = MODEM_CONNECT_TONES_ANSAM_PR; + awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); + false_hit = FALSE; + false_miss = FALSE; + for (pitch = 5; pitch < 25; pitch++) + { + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.mod_phase_rate = dds_phase_rate(pitch); + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); + for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) + { + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); + for (j = 0; j < samples; j++) + amp[j] += awgn(&chan_noise_source); + /*endfor*/ + modem_connect_tones_rx(&ans_pr_rx, amp, samples); + } + /*endfor*/ + hit = modem_connect_tones_rx_get(&ans_pr_rx); + if (pitch < (15 - 10) || pitch > (15 + 10)) + { + if (hit == tone_type) + false_hit = TRUE; + /*endif*/ + } + else if (pitch > (15 - AM_FREQ_TOLERANCE) && pitch < (15 + AM_FREQ_TOLERANCE)) + { + if (hit != tone_type) + false_miss = TRUE; + /*endif*/ + } + /*endif*/ + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + /*endif*/ + } + /*endfor*/ + if (false_hit || false_miss) + { + printf("Test failed.\n"); + exit(2); + } + /*endif*/ + printf("Test passed.\n"); + } + /*endif*/ + + if ((test_list & PERFORM_TEST_7A)) + { + printf("Test 7a: ANSam detection with AM depth\n"); + tone_type = MODEM_CONNECT_TONES_ANSAM; + pitch = 2100; + awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); + false_hit = FALSE; + false_miss = FALSE; + for (depth = 0; depth < 40; depth++) + { + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.mod_level = modem_tone_tx.level*depth/100; + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); + for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) + { + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); + for (j = 0; j < samples; j++) + amp[j] += awgn(&chan_noise_source); + /*endfor*/ + modem_connect_tones_rx(&ans_pr_rx, amp, samples); + } + /*endfor*/ + hit = modem_connect_tones_rx_get(&ans_pr_rx); + if (depth < 10) + { + if (hit == tone_type) + false_hit = TRUE; + /*endif*/ + } + else if (depth > 15) + { + if (hit != tone_type) + false_miss = TRUE; + /*endif*/ + } + /*endif*/ + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + /*endif*/ + } + /*endfor*/ + if (false_hit || false_miss) + { + printf("Test failed.\n"); + exit(2); + } + /*endif*/ + printf("Test passed.\n"); + } + /*endif*/ + + if ((test_list & PERFORM_TEST_7B)) + { + printf("Test 7b: ANSam/ (Modulated EC-disable) detection with AM depth\n"); + tone_type = MODEM_CONNECT_TONES_ANSAM_PR; + pitch = 2100; + awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); + false_hit = FALSE; + false_miss = FALSE; + for (depth = 0; depth < 40; depth++) + { + /* Use the transmitter to test the receiver */ + modem_connect_tones_tx_init(&modem_tone_tx, tone_type); + /* Fudge things for the test */ + modem_tone_tx.mod_level = modem_tone_tx.level*depth/100; + modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); + for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) + { + samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); + for (j = 0; j < samples; j++) + amp[j] += awgn(&chan_noise_source); + /*endfor*/ + modem_connect_tones_rx(&ans_pr_rx, amp, samples); + } + /*endfor*/ + hit = modem_connect_tones_rx_get(&ans_pr_rx); + if (depth < 10) + { + if (hit == tone_type) + false_hit = TRUE; + /*endif*/ + } + else if (depth > 15) + { + if (hit != tone_type) + false_miss = TRUE; + /*endif*/ + } + /*endif*/ + if (hit != MODEM_CONNECT_TONES_NONE) + printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); + /*endif*/ + } + /*endfor*/ + if (false_hit || false_miss) + { + printf("Test failed.\n"); + exit(2); + } + /*endif*/ + printf("Test passed.\n"); + } + /*endif*/ + + if ((test_list & PERFORM_TEST_8)) { /* Talk-off test */ /* Here we use the BellCore and Mitel talk off test tapes, intended for DTMF @@ -904,11 +1329,10 @@ int main(int argc, char *argv[]) might go easy on detectors looking for different pitches. However, the Mitel DTMF test tape is known (the hard way) to exercise 2280Hz tone detectors quite well. */ - printf("Test 6: Talk-off test\n"); + printf("Test 8: Talk-off test\n"); modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL); modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); - hits = 0; for (j = 0; bellcore_files[j][0]; j++) { if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL) @@ -976,7 +1400,7 @@ int main(int argc, char *argv[]) printf("Decode file '%s'\n", decode_test_file); modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, cng_detected, NULL); modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, ced_detected, NULL); - modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, ec_dis_detected, NULL); + modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, ans_pr_detected, NULL); hits = 0; if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) { diff --git a/libs/spandsp/tests/t38_gateway_tests.c b/libs/spandsp/tests/t38_gateway_tests.c index 7fa0f3e987..aa7b98e7d2 100644 --- a/libs/spandsp/tests/t38_gateway_tests.c +++ b/libs/spandsp/tests/t38_gateway_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_gateway_tests.c,v 1.82 2009/05/30 15:23:14 steveu Exp $ + * $Id: t38_gateway_tests.c,v 1.82.4.1 2009/12/19 09:47:57 steveu Exp $ */ /*! \file */ @@ -99,7 +99,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase B:", i); + snprintf(tag, sizeof(tag), "%c: Phase B", i); printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_rx_parameters(s, tag); return T30_ERR_OK; @@ -112,7 +112,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D:", i); + snprintf(tag, sizeof(tag), "%c: Phase D", i); printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); @@ -128,7 +128,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E:", i); + snprintf(tag, sizeof(tag), "%c: Phase E", i); printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); diff --git a/libs/spandsp/tests/t38_gateway_to_terminal_tests.c b/libs/spandsp/tests/t38_gateway_to_terminal_tests.c index 25b97da614..8c2e47c2d3 100644 --- a/libs/spandsp/tests/t38_gateway_to_terminal_tests.c +++ b/libs/spandsp/tests/t38_gateway_to_terminal_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_gateway_to_terminal_tests.c,v 1.66 2009/05/30 15:23:14 steveu Exp $ + * $Id: t38_gateway_to_terminal_tests.c,v 1.66.4.1 2009/12/19 09:47:57 steveu Exp $ */ /*! \file */ @@ -94,7 +94,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase B:", i); + snprintf(tag, sizeof(tag), "%c: Phase B", i); printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_rx_parameters(s, tag); return T30_ERR_OK; @@ -107,7 +107,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D:", i); + snprintf(tag, sizeof(tag), "%c: Phase D", i); printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); @@ -123,7 +123,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E:", i); + snprintf(tag, sizeof(tag), "%c: Phase E", i); printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); diff --git a/libs/spandsp/tests/t38_non_ecm_buffer_tests.c b/libs/spandsp/tests/t38_non_ecm_buffer_tests.c index a35cde7bb4..e8384c1f8c 100644 --- a/libs/spandsp/tests/t38_non_ecm_buffer_tests.c +++ b/libs/spandsp/tests/t38_non_ecm_buffer_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_non_ecm_buffer_tests.c,v 1.5 2009/04/25 14:17:47 steveu Exp $ + * $Id: t38_non_ecm_buffer_tests.c,v 1.5.4.1 2009/12/19 06:43:28 steveu Exp $ */ /*! \file */ @@ -50,6 +50,88 @@ module, used for T.38 gateways. #include "spandsp.h" +/* A pattern of widening gaps between ones, until at 11 apart an + EOL should be registered */ +static const uint8_t spreader[] = +{ + 0x55, + 0x55, + 0x55, + 0x55, + 0x55, + 0x55, + 0x55, + 0x55, /* 1 apart */ + 0x22, /* 2 and 3 apart */ + 0x10, /* 4 apart */ + 0x40, /* 5 apart */ + 0x80, /* 6 apart */ + 0x80, /* 7 apart */ + 0x40, /* 8 apart */ + 0x10, /* 9 apart */ + 0x02, /* 10 apart */ + 0x00, + 0x25 /* 11 apart */ +}; + +static int bit_no; + +static int xxx(t38_non_ecm_buffer_state_t *s, logging_state_t *l, int log_bits, int n, int expected) +{ + int i; + int j; + int bit; + + t38_non_ecm_buffer_inject(s, &spreader[n], 1); + if (expected >= 0) + { + for (i = 0; i < 128; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) s); + if (log_bits) + printf("Rx bit %d - %d\n", bit_no, bit); + if (bit != expected) + { + printf("Tests failed - %d %d %d\n", bit_no, bit, expected); + exit(2); + } + bit_no++; + } + } + else + { + j = -1; + for (i = 0; i < 256; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) s); + if (log_bits) + printf("Rx bit %d - %d\n", bit_no, bit); + if (j < 0) + { + if (bit == 1) + j = 18*8 - 5; + } + else + { + expected = (spreader[j >> 3] >> (7 - (j & 7))) & 1; + if (bit != expected) + { + printf("Tests failed - %d %d %d\n", bit_no, bit, expected); + exit(2); + } + j++; + if (j >= 18*8) + j = 0; + } + bit_no++; + if (j == 17*8) + return 0; + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + int main(int argc, char *argv[]) { t38_non_ecm_buffer_state_t buffer; @@ -60,65 +142,170 @@ int main(int argc, char *argv[]) int log_bits; int i; - log_bits = FALSE; + log_bits = (argc > 1); + printf("T.38 non-ECM rate adapting buffer tests.\n"); span_log_init(&logging, SPAN_LOG_FLOW, NULL); span_log_set_protocol(&logging, "Buffer"); + printf("1 - Impose no minimum for the bits per row\n"); t38_non_ecm_buffer_init(&buffer, TRUE, 0); - memset(buf, 0, sizeof(buf)); - memset(buf + 10, 0x55, 10); - buf[25] = 0x80; - memset(buf + 30, 0x55, 10); - t38_non_ecm_buffer_inject(&buffer, buf, 50); - t38_non_ecm_buffer_push(&buffer); n = 0; - do - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - } - while (bit >= 0); + bit_no = 0; + /* We should get ones until the buffers recognises an EOL */ + printf(" We should get ones here\n"); + for (i = 0; i < 17; i++) + xxx(&buffer, &logging, log_bits, i, 1); + printf(" We should change to zeros here\n"); + xxx(&buffer, &logging, log_bits, i, 0); + for (i = 0; i < 17; i++) + xxx(&buffer, &logging, log_bits, i, 0); + printf(" We should get the first row here\n"); + xxx(&buffer, &logging, log_bits, i, -1); + for (i = 0; i < 17; i++) + xxx(&buffer, &logging, log_bits, i, 0); + printf(" We should get the second row here\n"); + xxx(&buffer, &logging, log_bits, i, -1); + for (i = 0; i < 17; i++) + xxx(&buffer, &logging, log_bits, i, 0); + printf(" We should get the third row here\n"); + xxx(&buffer, &logging, log_bits, i, -1); + printf(" Done\n"); t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + printf("2 - Impose no minimum for the bits per row, different alignment\n"); t38_non_ecm_buffer_init(&buffer, TRUE, 0); + n = 0; memset(buf, 0, sizeof(buf)); + /* The first one in this should be seen as the first EOL */ memset(buf + 10, 0x55, 10); - buf[25] = 0x40; + /* EOL 2 */ + buf[25] = 0x20; + /* EOL 3 */ memset(buf + 30, 0x55, 10); + /* EOL 4 */ + buf[45] = 0x10; t38_non_ecm_buffer_inject(&buffer, buf, 50); t38_non_ecm_buffer_push(&buffer); - n = 0; - do + for (;;) { bit = t38_non_ecm_buffer_get_bit((void *) &buffer); if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); + printf("Rx bit %d - %d\n", n, bit); + n++; + if (bit == SIG_STATUS_END_OF_DATA) + { + if (n != 337) + { + printf("Tests failed\n"); + exit(2); + } + break; + } + if (n >= 18 && n <= 96) + { + if (bit == (n & 1)) + { + printf("Tests failed\n"); + exit(2); + } + } + else if (n >= 178 && n <= 256) + { + if (bit == (n & 1)) + { + printf("Tests failed\n"); + exit(2); + } + } + else if (n == 139 || n == 300) + { + if (bit != 1) + { + printf("Tests failed\n"); + exit(2); + } + } + else + { + if (bit != 0) + { + printf("Tests failed\n"); + exit(2); + } + } } - while (bit >= 0); t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + printf("3 - Demand a fairly high minimum for the bits per row\n"); t38_non_ecm_buffer_init(&buffer, TRUE, 400); + n = 0; memset(buf, 0, sizeof(buf)); + /* The first one in this should be seen as the first EOL */ memset(buf + 10, 0x55, 10); - buf[25] = 0x01; + /* EOL 2 */ + buf[25] = 0x08; + /* EOL 3 */ memset(buf + 30, 0x55, 10); + /* EOL 4 */ + buf[45] = 0x04; t38_non_ecm_buffer_inject(&buffer, buf, 50); t38_non_ecm_buffer_push(&buffer); - n = 0; - do + for (;;) { bit = t38_non_ecm_buffer_get_bit((void *) &buffer); if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); + printf("Rx bit %d - %d\n", n, bit); + n++; + if (bit == SIG_STATUS_END_OF_DATA) + { + if (n != 1273) + { + printf("Tests failed\n"); + exit(2); + } + break; + } + if (n >= 18 && n <= 96) + { + if (bit == (n & 1)) + { + printf("Tests failed\n"); + exit(2); + } + } + else if (n >= 834 && n <= 912) + { + if (bit == (n & 1)) + { + printf("Tests failed\n"); + exit(2); + } + } + else if (n == 429 || n == 1238) + { + if (bit != 1) + { + printf("Tests failed\n"); + exit(2); + } + } + else + { + if (bit != 0) + { + printf("Tests failed\n"); + exit(2); + } + } } - while (bit >= 0); t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + printf("4 - Take some time to get to the first row of the image, output ahead\n"); t38_non_ecm_buffer_init(&buffer, TRUE, 400); + n = 0; /* Get some initial bits from an empty buffer. These should be ones */ for (i = 0; i < 1000; i++) { @@ -131,6 +318,7 @@ int main(int argc, char *argv[]) exit(2); } } + printf(" Initial ones OK\n"); /* Now put some zeros into the buffer, but no EOL. We should continue getting ones out. */ memset(buf, 0, sizeof(buf)); @@ -146,6 +334,7 @@ int main(int argc, char *argv[]) exit(2); } } + printf(" Continuing initial ones OK\n"); /* Now add a one, to make an EOL. We should see the zeros come out. */ buf[0] = 0x01; t38_non_ecm_buffer_inject(&buffer, buf, 1); @@ -160,8 +349,9 @@ int main(int argc, char *argv[]) exit(2); } } + printf(" First EOL caused zeros to output OK\n"); /* Now add another line. We should see the first line come out. This means just the - eighth bit from now will be a one. */ + 23rd bit from now will be a one. */ buf[0] = 0x00; buf[4] = 0x01; t38_non_ecm_buffer_inject(&buffer, buf, 5); @@ -170,12 +360,343 @@ int main(int argc, char *argv[]) bit = t38_non_ecm_buffer_get_bit((void *) &buffer); if (log_bits) printf("Rx bit %d - %d\n", n++, bit); - if (i != 7 && bit != 0) + if ((i == 23 && bit == 0) || (i != 23 && bit != 0)) { printf("Tests failed (%d)\n", i); exit(2); } } + printf(" Second EOL caused the first row to output OK\n"); + /* Now inject an RTC - 6 EOLs */ + memset(buf, 0, sizeof(buf)); + /* T.4 1D style */ + for (i = 10; i < 19; i += 3) + { + buf[i] = 0x00; + buf[i + 1] = 0x10; + buf[i + 2] = 0x01; + } + /* T.4 2D style */ + buf[25 + 0] = 0x00; + buf[25 + 1] = 0x18; + buf[25 + 2] = 0x00; + buf[25 + 3] = 0xC0; + buf[25 + 4] = 0x06; + buf[25 + 5] = 0x00; + buf[25 + 6] = 0x30; + buf[25 + 7] = 0x01; + buf[25 + 8] = 0x80; + buf[25 + 9] = 0x0C; + t38_non_ecm_buffer_inject(&buffer, buf, 50); + t38_non_ecm_buffer_push(&buffer); + for (i = 0; i < 1000; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (i == 7 + || + i == 400 + 11 + 0*12 + || + i == 400 + 11 + 1*12 + || + i == 400 + 11 + 2*12 + || + i == 400 + 11 + 3*12 + || + i == 400 + 11 + 4*12 + || + i == 400 + 11 + 5*12 + || + i == 400 + 11 + 60 + 400 + 4 + 0*13 + || + i == 400 + 11 + 60 + 400 + 4 + 0*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 1*13 + || + i == 400 + 11 + 60 + 400 + 4 + 1*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 2*13 + || + i == 400 + 11 + 60 + 400 + 4 + 2*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 3*13 + || + i == 400 + 11 + 60 + 400 + 4 + 3*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 4*13 + || + i == 400 + 11 + 60 + 400 + 4 + 4*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 5*13 + || + i == 400 + 11 + 60 + 400 + 4 + 5*13 + 1) + { + if (bit == 0) + { + printf("Tests failed (%d)\n", i); + exit(2); + } + } + else + { + if (bit == 1) + { + printf("Tests failed (%d)\n", i); + exit(2); + } + } + } + printf(" RTC output OK\n"); + t38_non_ecm_buffer_report_input_status(&buffer, &logging); + t38_non_ecm_buffer_report_output_status(&buffer, &logging); + + printf("5 - Take some time to get to the first row of the image, output behind\n"); + t38_non_ecm_buffer_init(&buffer, TRUE, 400); + n = 0; + /* Inject some ones. */ + memset(buf, 0xFF, 100); + t38_non_ecm_buffer_inject(&buffer, buf, 100); + /* Inject some zeros */ + memset(buf, 0, sizeof(buf)); + t38_non_ecm_buffer_inject(&buffer, buf, 100); + for (i = 0; i < 1000; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (bit != 1) + { + printf("Tests failed\n"); + exit(2); + } + } + printf(" Initial ones OK\n"); + /* Now add a one, to make an EOL. We should see the zeros come out. */ + buf[0] = 0x01; + t38_non_ecm_buffer_inject(&buffer, buf, 1); + for (i = 0; i < 1000; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (bit != 0) + { + printf("Tests failed\n"); + exit(2); + } + } + printf(" First EOL caused zeros to output OK\n"); + /* Now add another line. We should see the first line come out. This means just the + 23rd bit from now will be a one. */ + buf[0] = 0x00; + buf[4] = 0x01; + t38_non_ecm_buffer_inject(&buffer, buf, 5); + for (i = 0; i < 1000; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if ((i == 23 && bit == 0) || (i != 23 && bit != 0)) + { + printf("Tests failed (%d)\n", i); + exit(2); + } + } + printf(" Second EOL caused the first row to output OK\n"); + /* Now inject an RTC - 6 EOLs */ + memset(buf, 0, sizeof(buf)); + /* T.4 1D style */ + for (i = 10; i < 19; i += 3) + { + buf[i] = 0x00; + buf[i + 1] = 0x10; + buf[i + 2] = 0x01; + } + /* T.4 2D style */ + buf[25 + 0] = 0x00; + buf[25 + 1] = 0x18; + buf[25 + 2] = 0x00; + buf[25 + 3] = 0xC0; + buf[25 + 4] = 0x06; + buf[25 + 5] = 0x00; + buf[25 + 6] = 0x30; + buf[25 + 7] = 0x01; + buf[25 + 8] = 0x80; + buf[25 + 9] = 0x0C; + t38_non_ecm_buffer_inject(&buffer, buf, 50); + t38_non_ecm_buffer_push(&buffer); + for (i = 0; i < 1000; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (i == 7 + || + i == 400 + 11 + 0*12 + || + i == 400 + 11 + 1*12 + || + i == 400 + 11 + 2*12 + || + i == 400 + 11 + 3*12 + || + i == 400 + 11 + 4*12 + || + i == 400 + 11 + 5*12 + || + i == 400 + 11 + 60 + 400 + 4 + 0*13 + || + i == 400 + 11 + 60 + 400 + 4 + 0*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 1*13 + || + i == 400 + 11 + 60 + 400 + 4 + 1*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 2*13 + || + i == 400 + 11 + 60 + 400 + 4 + 2*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 3*13 + || + i == 400 + 11 + 60 + 400 + 4 + 3*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 4*13 + || + i == 400 + 11 + 60 + 400 + 4 + 4*13 + 1 + || + i == 400 + 11 + 60 + 400 + 4 + 5*13 + || + i == 400 + 11 + 60 + 400 + 4 + 5*13 + 1) + { + if (bit == 0) + { + printf("Tests failed (%d)\n", i); + exit(2); + } + } + else + { + if (bit == 1) + { + printf("Tests failed (%d)\n", i); + exit(2); + } + } + } + printf(" RTC output OK\n"); + t38_non_ecm_buffer_report_input_status(&buffer, &logging); + t38_non_ecm_buffer_report_output_status(&buffer, &logging); + + printf("6 - TCF without leading ones\n"); + t38_non_ecm_buffer_init(&buffer, FALSE, 400); + n = 0; + /* Get some initial bits from an empty buffer. These should be ones */ + for (i = 0; i < 1000; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (bit != 1) + { + printf("Tests failed\n"); + exit(2); + } + } + printf(" Initial ones from an empty TCF buffer OK\n"); + /* Now send some TCF through, and see that it comes out */ + memset(buf, 0x00, sizeof(buf)); + t38_non_ecm_buffer_inject(&buffer, buf, 500); + t38_non_ecm_buffer_push(&buffer); + for (i = 0; i < 500*8; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (bit != 0) + { + printf("Tests failed\n"); + exit(2); + } + } + printf(" Passthrough of TCF OK\n"); + /* Check the right number of bits was buffered */ + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (bit != SIG_STATUS_END_OF_DATA) + { + printf("Tests failed\n"); + exit(2); + } + printf(" End of data seen OK\n"); + t38_non_ecm_buffer_report_input_status(&buffer, &logging); + t38_non_ecm_buffer_report_output_status(&buffer, &logging); + + printf("7 - TCF with leading ones\n"); + t38_non_ecm_buffer_init(&buffer, FALSE, 400); + n = 0; + /* Get some initial bits from an empty buffer. These should be ones */ + for (i = 0; i < 1000; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (bit != 1) + { + printf("Tests failed\n"); + exit(2); + } + } + printf(" Initial ones from an empty TCF buffer OK\n"); + + /* Now send some initial ones, and see that we continue to get all ones + as the stuffing. */ + memset(buf, 0xFF, 500); + t38_non_ecm_buffer_inject(&buffer, buf, 500); + for (i = 0; i < 500*8; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (bit != 1) + { + printf("Tests failed\n"); + exit(2); + } + } + printf(" Sustaining ones OK\n"); + + /* Now send some initial ones, and some TCF through, and see that only + the TCF comes out */ + memset(buf, 0x00, sizeof(buf)); + memset(buf, 0xFF, 100); + /* End the ones mid byte */ + buf[100] = 0xF0; + t38_non_ecm_buffer_inject(&buffer, buf, 500); + t38_non_ecm_buffer_push(&buffer); + for (i = 0; i < 400*8; i++) + { + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if ((i < 4 && bit == 0) || (i >= 4 && bit != 0)) + { + printf("Tests failed\n"); + exit(2); + } + } + printf(" Passthrough of TCF OK\n"); + /* Check the right number of bits was buffered */ + bit = t38_non_ecm_buffer_get_bit((void *) &buffer); + if (log_bits) + printf("Rx bit %d - %d\n", n++, bit); + if (bit != SIG_STATUS_END_OF_DATA) + { + printf("Tests failed\n"); + exit(2); + } + printf(" End of data seen OK\n"); t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); diff --git a/libs/spandsp/tests/t38_terminal_tests.c b/libs/spandsp/tests/t38_terminal_tests.c index 7d2c204b53..9dbece39a7 100644 --- a/libs/spandsp/tests/t38_terminal_tests.c +++ b/libs/spandsp/tests/t38_terminal_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_terminal_tests.c,v 1.67 2009/04/25 14:34:45 steveu Exp $ + * $Id: t38_terminal_tests.c,v 1.67.4.1 2009/12/19 09:47:57 steveu Exp $ */ /*! \file */ @@ -90,7 +90,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase B:", i); + snprintf(tag, sizeof(tag), "%c: Phase B", i); printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_rx_parameters(s, tag); return T30_ERR_OK; @@ -103,7 +103,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D:", i); + snprintf(tag, sizeof(tag), "%c: Phase D", i); printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); @@ -119,7 +119,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E:", i); + snprintf(tag, sizeof(tag), "%c: Phase E", i); printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); diff --git a/libs/spandsp/tests/t38_terminal_to_gateway_tests.c b/libs/spandsp/tests/t38_terminal_to_gateway_tests.c index bb5ce8ef2a..f982f90926 100644 --- a/libs/spandsp/tests/t38_terminal_to_gateway_tests.c +++ b/libs/spandsp/tests/t38_terminal_to_gateway_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t38_terminal_to_gateway_tests.c,v 1.65 2009/05/30 15:23:14 steveu Exp $ + * $Id: t38_terminal_to_gateway_tests.c,v 1.65.4.1 2009/12/19 09:47:57 steveu Exp $ */ /*! \file */ @@ -94,7 +94,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase B:", i); + snprintf(tag, sizeof(tag), "%c: Phase B", i); printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_rx_parameters(s, tag); return T30_ERR_OK; @@ -107,7 +107,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D:", i); + snprintf(tag, sizeof(tag), "%c: Phase D", i); printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); @@ -123,7 +123,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E:", i); + snprintf(tag, sizeof(tag), "%c: Phase E", i); printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); diff --git a/libs/spandsp/tests/t4_tests.c b/libs/spandsp/tests/t4_tests.c index df90f3fb4d..6d6830e9de 100644 --- a/libs/spandsp/tests/t4_tests.c +++ b/libs/spandsp/tests/t4_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: t4_tests.c,v 1.69 2009/05/16 03:34:45 steveu Exp $ + * $Id: t4_tests.c,v 1.69.4.1 2009/12/19 09:47:57 steveu Exp $ */ /*! \file */ @@ -129,8 +129,8 @@ static void display_page_stats(t4_state_t *s) t4_get_transfer_statistics(s, &stats); printf("Pages = %d\n", stats.pages_transferred); - printf("Image size = %d x %d pixels\n", stats.width, stats.length); - printf("Image resolution = %d/m x %d/m\n", stats.x_resolution, stats.y_resolution); + printf("Image size = %d pels x %d pels\n", stats.width, stats.length); + printf("Image resolution = %d pels/m x %d pels/m\n", stats.x_resolution, stats.y_resolution); printf("Bad rows = %d\n", stats.bad_rows); printf("Longest bad row run = %d\n", stats.longest_bad_row_run); printf("Bits per row - min %d, max %d\n", s->min_row_bits, s->max_row_bits); @@ -144,6 +144,7 @@ static int row_read_handler(void *user_data, uint8_t buf[], size_t len) const char *s; static int row = 0; + /* Send the test pattern. */ s = t4_test_patterns[row++]; if (row >= 16) return 0; @@ -170,6 +171,7 @@ static int row_write_handler(void *user_data, const uint8_t buf[], size_t len) static int row = 0; uint8_t ref[8192]; + /* Verify that what is received matches the test pattern. */ if (len == 0) return 0; s = t4_test_patterns[row++]; @@ -280,9 +282,15 @@ int main(int argc, char *argv[]) { static const int compression_sequence[] = { + //T4_COMPRESSION_NONE, T4_COMPRESSION_ITU_T4_1D, T4_COMPRESSION_ITU_T4_2D, - T4_COMPRESSION_ITU_T6 + T4_COMPRESSION_ITU_T6, + //T4_COMPRESSION_ITU_T85, + //T4_COMPRESSION_ITU_T43, + //T4_COMPRESSION_ITU_T45, + //T4_COMPRESSION_ITU_T81, + //T4_COMPRESSION_ITU_SYCC_T81 }; int sends; int page_no; @@ -486,11 +494,11 @@ int main(int argc, char *argv[]) } span_log_set_level(&receive_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); t4_rx_set_row_write_handler(&receive_state, row_write_handler, NULL); + t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state)); t4_rx_set_x_resolution(&receive_state, t4_tx_get_x_resolution(&send_state)); t4_rx_set_y_resolution(&receive_state, t4_tx_get_y_resolution(&send_state)); - t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state)); - /* Now send and receive all the pages in the source TIFF file */ + /* Now send and receive the test data with all compression modes. */ page_no = 1; /* If we are stepping around the compression schemes, reset to the start of the sequence. */ if (compression_step > 0) diff --git a/libs/spandsp/tests/tsb85_tests.sh b/libs/spandsp/tests/tsb85_tests.sh index a9f6c9ff21..31cf6aedae 100755 --- a/libs/spandsp/tests/tsb85_tests.sh +++ b/libs/spandsp/tests/tsb85_tests.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # spandsp fax tests # diff --git a/libs/spandsp/tests/v8_tests.c b/libs/spandsp/tests/v8_tests.c index ab6006ce88..4eca4fefc5 100644 --- a/libs/spandsp/tests/v8_tests.c +++ b/libs/spandsp/tests/v8_tests.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: v8_tests.c,v 1.33 2009/05/30 15:23:14 steveu Exp $ + * $Id: v8_tests.c,v 1.36 2009/11/04 16:10:14 steveu Exp $ */ /*! \page v8_tests_page V.8 tests @@ -70,30 +70,303 @@ static void handler(void *user_data, v8_result_t *result) printf("%s V.8 negotiation failed\n", s); return; } - printf("%s V.8 negotiation result:\n", s); - printf(" Call function '%s'\n", v8_call_function_to_str(result->call_function)); - printf(" Negotiated modulation '%s'\n", v8_modulation_to_str(result->negotiated_modulation)); - printf(" Protocol '%s'\n", v8_protocol_to_str(result->protocol)); - printf(" PSTN access '%s'\n", v8_pstn_access_to_str(result->pstn_access)); - printf(" PCM modem availability '%s'\n", v8_pcm_modem_availability_to_str(result->pcm_modem_availability)); - if (result->call_function == V8_CALL_V_SERIES - && - result->negotiated_modulation == V8_MOD_V90 - && - result->protocol == V8_PROTOCOL_LAPM_V42) + if (result->modem_connect_tone_detected == MODEM_CONNECT_TONES_ANSAM + || + result->modem_connect_tone_detected == MODEM_CONNECT_TONES_ANSAM_PR + || + result->modem_connect_tone_detected == MODEM_CONNECT_TONES_NONE) { - negotiations_ok++; + printf("%s V.8 negotiation result:\n", s); + printf(" Modem connect tone '%s'\n", modem_connect_tone_to_str(result->modem_connect_tone_detected)); + printf(" Call function '%s'\n", v8_call_function_to_str(result->call_function)); + printf(" Negotiated modulation '%s'\n", v8_modulation_to_str(result->negotiated_modulation)); + printf(" Protocol '%s'\n", v8_protocol_to_str(result->protocol)); + printf(" PSTN access '%s'\n", v8_pstn_access_to_str(result->pstn_access)); + printf(" NSF %d %d\n", result->nsf_seen, result->nsf); + printf(" PCM modem availability '%s'\n", v8_pcm_modem_availability_to_str(result->pcm_modem_availability)); + printf(" T.66 %d %d\n", result->t66_seen, result->t66); + if (result->call_function == V8_CALL_V_SERIES + && + result->negotiated_modulation == V8_MOD_V90 + && + result->protocol == V8_PROTOCOL_LAPM_V42) + { + negotiations_ok++; + } + } + else + { + printf("%s V.8 negotiation result:\n", s); + printf(" Modem connect tone '%s'\n", modem_connect_tone_to_str(result->modem_connect_tone_detected)); } } +/*- End of function --------------------------------------------------------*/ + +static int v8_calls_v8_tests(SNDFILE *outhandle) +{ + v8_state_t *v8_caller; + v8_state_t *v8_answerer; + logging_state_t *caller_logging; + logging_state_t *answerer_logging; + int caller_available_modulations; + int answerer_available_modulations; + int i; + int samples; + int remnant; + int outframes; + int16_t amp[SAMPLES_PER_CHUNK]; + int16_t out_amp[2*SAMPLES_PER_CHUNK]; + + caller_available_modulations = V8_MOD_V17 + | V8_MOD_V21 + | V8_MOD_V22 + | V8_MOD_V23HALF + | V8_MOD_V23 + | V8_MOD_V26BIS + | V8_MOD_V26TER + | V8_MOD_V27TER + | V8_MOD_V29 + | V8_MOD_V32 + | V8_MOD_V34HALF + | V8_MOD_V34 + | V8_MOD_V90 + | V8_MOD_V92; + answerer_available_modulations = V8_MOD_V17 + | V8_MOD_V21 + | V8_MOD_V22 + | V8_MOD_V23HALF + | V8_MOD_V23 + | V8_MOD_V26BIS + | V8_MOD_V26TER + | V8_MOD_V27TER + | V8_MOD_V29 + | V8_MOD_V32 + | V8_MOD_V34HALF + | V8_MOD_V34 + | V8_MOD_V90 + | V8_MOD_V92; + negotiations_ok = 0; + + v8_caller = v8_init(NULL, TRUE, TRUE, caller_available_modulations, handler, (void *) "caller"); + v8_answerer = v8_init(NULL, FALSE, TRUE, answerer_available_modulations, handler, (void *) "answerer"); + caller_logging = v8_get_logging_state(v8_caller); + span_log_set_level(caller_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); + span_log_set_tag(caller_logging, "caller"); + answerer_logging = v8_get_logging_state(v8_answerer); + span_log_set_level(answerer_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); + span_log_set_tag(answerer_logging, "answerer"); + for (i = 0; i < 1000; i++) + { + samples = v8_tx(v8_caller, amp, SAMPLES_PER_CHUNK); + if (samples < SAMPLES_PER_CHUNK) + { + memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples)); + samples = SAMPLES_PER_CHUNK; + } + span_log_bump_samples(caller_logging, samples); + remnant = v8_rx(v8_answerer, amp, samples); + for (i = 0; i < samples; i++) + out_amp[2*i] = amp[i]; + + samples = v8_tx(v8_answerer, amp, SAMPLES_PER_CHUNK); + if (samples < SAMPLES_PER_CHUNK) + { + memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples)); + samples = SAMPLES_PER_CHUNK; + } + span_log_bump_samples(answerer_logging, samples); + if (v8_rx(v8_caller, amp, samples) && remnant) + break; + for (i = 0; i < samples; i++) + out_amp[2*i + 1] = amp[i]; + + outframes = sf_writef_short(outhandle, out_amp, samples); + if (outframes != samples) + { + fprintf(stderr, " Error writing audio file\n"); + exit(2); + } + } + v8_free(v8_caller); + v8_free(v8_answerer); + + if (negotiations_ok != 2) + { + printf("Tests failed.\n"); + exit(2); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int non_v8_calls_v8_tests(SNDFILE *outhandle) +{ + silence_gen_state_t *non_v8_caller_tx; + modem_connect_tones_rx_state_t *non_v8_caller_rx; + v8_state_t *v8_answerer; + logging_state_t *answerer_logging; + int answerer_available_modulations; + int i; + int samples; + int remnant; + int outframes; + int tone; + int16_t amp[SAMPLES_PER_CHUNK]; + int16_t out_amp[2*SAMPLES_PER_CHUNK]; + + answerer_available_modulations = V8_MOD_V17 + | V8_MOD_V21 + | V8_MOD_V22 + | V8_MOD_V23HALF + | V8_MOD_V23 + | V8_MOD_V26BIS + | V8_MOD_V26TER + | V8_MOD_V27TER + | V8_MOD_V29 + | V8_MOD_V32 + | V8_MOD_V34HALF + | V8_MOD_V34 + | V8_MOD_V90 + | V8_MOD_V92; + negotiations_ok = 0; + + non_v8_caller_tx = silence_gen_init(NULL, 10*SAMPLE_RATE); + non_v8_caller_rx = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); + v8_answerer = v8_init(NULL, FALSE, TRUE, answerer_available_modulations, handler, (void *) "answerer"); + answerer_logging = v8_get_logging_state(v8_answerer); + span_log_set_level(answerer_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); + span_log_set_tag(answerer_logging, "answerer"); + for (i = 0; i < 1000; i++) + { + samples = silence_gen(non_v8_caller_tx, amp, SAMPLES_PER_CHUNK); + if (samples < SAMPLES_PER_CHUNK) + { + memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples)); + samples = SAMPLES_PER_CHUNK; + } + remnant = v8_rx(v8_answerer, amp, samples); + if (remnant) + break; + for (i = 0; i < samples; i++) + out_amp[2*i] = amp[i]; + + samples = v8_tx(v8_answerer, amp, SAMPLES_PER_CHUNK); + if (samples < SAMPLES_PER_CHUNK) + { + memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples)); + samples = SAMPLES_PER_CHUNK; + } + span_log_bump_samples(answerer_logging, samples); + modem_connect_tones_rx(non_v8_caller_rx, amp, samples); + if ((tone = modem_connect_tones_rx_get(non_v8_caller_rx)) != MODEM_CONNECT_TONES_NONE) + { + printf("Detected %s (%d)\n", modem_connect_tone_to_str(tone), tone); + if (tone == MODEM_CONNECT_TONES_ANSAM_PR) + negotiations_ok++; + } + for (i = 0; i < samples; i++) + out_amp[2*i + 1] = amp[i]; + + outframes = sf_writef_short(outhandle, out_amp, samples); + if (outframes != samples) + { + fprintf(stderr, " Error writing audio file\n"); + exit(2); + } + } + silence_gen_free(non_v8_caller_tx); + modem_connect_tones_rx_free(non_v8_caller_rx); + v8_free(v8_answerer); + + if (negotiations_ok != 1) + { + printf("Tests failed.\n"); + exit(2); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int v8_calls_non_v8_tests(SNDFILE *outhandle) +{ + v8_state_t *v8_caller; + modem_connect_tones_tx_state_t *non_v8_answerer_tx; + logging_state_t *caller_logging; + int caller_available_modulations; + int i; + int samples; + int outframes; + int16_t amp[SAMPLES_PER_CHUNK]; + int16_t out_amp[2*SAMPLES_PER_CHUNK]; + + caller_available_modulations = V8_MOD_V17 + | V8_MOD_V21 + | V8_MOD_V22 + | V8_MOD_V23HALF + | V8_MOD_V23 + | V8_MOD_V26BIS + | V8_MOD_V26TER + | V8_MOD_V27TER + | V8_MOD_V29 + | V8_MOD_V32 + | V8_MOD_V34HALF + | V8_MOD_V34 + | V8_MOD_V90 + | V8_MOD_V92; + negotiations_ok = 0; + + v8_caller = v8_init(NULL, TRUE, TRUE, caller_available_modulations, handler, (void *) "caller"); + non_v8_answerer_tx = modem_connect_tones_tx_init(NULL, MODEM_CONNECT_TONES_ANS_PR); + caller_logging = v8_get_logging_state(v8_caller); + span_log_set_level(caller_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); + span_log_set_tag(caller_logging, "caller"); + for (i = 0; i < 1000; i++) + { + samples = v8_tx(v8_caller, amp, SAMPLES_PER_CHUNK); + if (samples < SAMPLES_PER_CHUNK) + { + memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples)); + samples = SAMPLES_PER_CHUNK; + } + span_log_bump_samples(caller_logging, samples); + for (i = 0; i < samples; i++) + out_amp[2*i] = amp[i]; + + samples = modem_connect_tones_tx(non_v8_answerer_tx, amp, SAMPLES_PER_CHUNK); + if (samples < SAMPLES_PER_CHUNK) + { + memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples)); + samples = SAMPLES_PER_CHUNK; + } + if (v8_rx(v8_caller, amp, samples)) + break; + for (i = 0; i < samples; i++) + out_amp[2*i + 1] = amp[i]; + + outframes = sf_writef_short(outhandle, out_amp, samples); + if (outframes != samples) + { + fprintf(stderr, " Error writing audio file\n"); + exit(2); + } + } + v8_free(v8_caller); + modem_connect_tones_tx_free(non_v8_answerer_tx); + +#if 0 + if (negotiations_ok != 1) + { + printf("Tests failed.\n"); + exit(2); + } +#endif + return 0; +} +/*- End of function --------------------------------------------------------*/ int main(int argc, char *argv[]) { - int i; int16_t amp[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - v8_state_t *v8_caller; - v8_state_t *v8_answerer; - int outframes; int samples; int remnant; int caller_available_modulations; @@ -102,6 +375,7 @@ int main(int argc, char *argv[]) SNDFILE *outhandle; int opt; char *decode_test_file; + v8_state_t *v8_answerer; logging_state_t *logging; decode_test_file = NULL; @@ -155,65 +429,28 @@ int main(int argc, char *argv[]) fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME); exit(2); } - - v8_caller = v8_init(NULL, TRUE, caller_available_modulations, handler, (void *) "caller"); - v8_answerer = v8_init(NULL, FALSE, answerer_available_modulations, handler, (void *) "answerer"); - logging = v8_get_logging_state(v8_caller); - span_log_set_level(logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG); - span_log_set_tag(logging, "caller"); - logging = v8_get_logging_state(v8_answerer); - span_log_set_level(logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG); - span_log_set_tag(logging, "answerer"); - for (i = 0; i < 1000; i++) - { - samples = v8_tx(v8_caller, amp, SAMPLES_PER_CHUNK); - if (samples < SAMPLES_PER_CHUNK) - { - memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples)); - samples = SAMPLES_PER_CHUNK; - } - remnant = v8_rx(v8_answerer, amp, samples); - for (i = 0; i < samples; i++) - out_amp[2*i] = amp[i]; - - samples = v8_tx(v8_answerer, amp, SAMPLES_PER_CHUNK); - if (samples < SAMPLES_PER_CHUNK) - { - memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples)); - samples = SAMPLES_PER_CHUNK; - } - if (v8_rx(v8_caller, amp, samples) && remnant) - break; - for (i = 0; i < samples; i++) - out_amp[2*i + 1] = amp[i]; - - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } + + printf("Test 1: V.8 terminal calls V.8 terminal\n"); + v8_calls_v8_tests(outhandle); + + printf("Test 2: non-V.8 terminal calls V.8 terminal\n"); + non_v8_calls_v8_tests(outhandle); + + printf("Test 3: V.8 terminal calls non-V.8 terminal\n"); + v8_calls_non_v8_tests(outhandle); + if (sf_close(outhandle)) { fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); exit(2); } - v8_free(v8_caller); - v8_free(v8_answerer); - - if (negotiations_ok != 2) - { - printf("Tests failed.\n"); - exit(2); - } printf("Tests passed.\n"); } else { printf("Decode file '%s'\n", decode_test_file); - v8_answerer = v8_init(NULL, FALSE, answerer_available_modulations, handler, (void *) "answerer"); + v8_answerer = v8_init(NULL, FALSE, TRUE, answerer_available_modulations, handler, (void *) "answerer"); logging = v8_get_logging_state(v8_answerer); span_log_set_level(logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG); span_log_set_tag(logging, "decoder");